diff --git a/specs/03-Data-and-Storage/n8n.workflow.json b/specs/03-Data-and-Storage/n8n.workflow.json index 2243aa0..2988b66 100644 --- a/specs/03-Data-and-Storage/n8n.workflow.json +++ b/specs/03-Data-and-Storage/n8n.workflow.json @@ -28,42 +28,38 @@ { "fieldLabel": "Batch Size", "fieldType": "number", - "placeholder": "2", - "requiredField": false + "placeholder": "2" }, { "fieldLabel": "Excel File Path", - "fieldType": "text", - "placeholder": "/home/node/.n8n-files/staging_ai/C22024.xlsx", - "requiredField": false + "placeholder": "/home/node/.n8n-files/staging_ai/C22024.xlsx" } ] }, - "responseMode": "onReceived", "options": {} }, - "id": "9e2cd13c-4d26-4bd8-98e3-128cbd6bcfcc", + "id": "4609ab68-f7e4-4800-ad39-19ce32de60d0", "name": "Form Trigger", "type": "n8n-nodes-base.formTrigger", "typeVersion": 2.2, "position": [ - 14208, - 6800 + 31024, + 13504 ], - "webhookId": "lcbp3-migration-form", + "webhookId": "e164a362-0c6b-4243-a5ad-b325aa943f4f", "notes": "เปิด URL เพื่อเลือก Model ก่อนรัน" }, { "parameters": { "jsCode": "// Read model selected from Form Trigger dropdown\nconst formData = $('Form Trigger').first()?.json || {};\nconst selectedModelLabel = String(formData['Ollama Model (Primary)'] || '');\n\n// Extract just the model ID (before the space in the label)\nconst MODEL_MAP = {\n 'qwen2.5:7b-instruct-q4_K_M (สมดุล - แนะนำ)': 'qwen2.5:7b-instruct-q4_K_M',\n 'scb10x/typhoon2.1-gemma3-4b (เร็ว + ไทยดี)': 'scb10x/typhoon2.1-gemma3-4b',\n 'promptnow/openthaigpt1.5-7b-instruct-q4_k_m (ไทยเฉพาะทาง)': 'promptnow/openthaigpt1.5-7b-instruct-q4_k_m'\n};\nconst selectedModel = MODEL_MAP[selectedModelLabel] || 'qwen2.5:7b-instruct-q4_K_M';\n\nconst batchSizeInput = parseInt(formData['Batch Size'] || '0');\nconst excelFileInput = String(formData['Excel File Path'] || '').trim();\n\nconst CONFIG = {\n // Ollama Settings\n OLLAMA_HOST: 'http://192.168.20.100:11434',\n // Model selected from Form UI\n OLLAMA_MODEL_PRIMARY: selectedModel,\n // Fallback\n OLLAMA_MODEL_FALLBACK: 'mistral:7b-instruct-q4_K_M',\n \n // Backend Settings\n BACKEND_URL: 'https://backend.np-dms.work',\n MIGRATION_TOKEN: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Im1pZ3JhdGlvbl9ib3QiLCJzdWIiOjUsInNjb3BlIjoiR2xvYmFsIiwiaWF0IjoxNzcyNzc0MzI5LCJleHAiOjQ5Mjg1MzQzMjl9.TtA8zoHy7G9J5jPgYQPv7yw-9X--B_hl-Nv-c9V4PaA',\n \n // Batch Settings\n BATCH_SIZE: batchSizeInput > 0 ? batchSizeInput : 2,\n BATCH_ID: (() => { const d = new Date(Date.now() + 7 * 3600000); const s = d.toISOString(); return s.substring(0,10).replace(/-/g,'') + ':' + s.substring(11,16).replace(/:/g,''); })(),\n DELAY_MS: 2000,\n \n // Thresholds\n CONFIDENCE_HIGH: 0.85,\n CONFIDENCE_LOW: 0.60,\n MAX_RETRY: 3,\n FALLBACK_THRESHOLD: 5,\n \n // Source Definitions - แก้ไขโฟลเดอร์และไฟล์ทำงานที่นี่\n EXCEL_FILE: excelFileInput || '/home/node/.n8n-files/staging_ai/C22024.xlsx',\n SOURCE_PDF_DIR: '/home/node/.n8n-files/staging_ai/Incoming/08C.2/2567',\n LOG_PATH: '/home/node/.n8n-files/migration_logs',\n \n // Database\n DB_HOST: '192.168.10.8',\n DB_PORT: 3306,\n DB_NAME: 'lcbp3',\n DB_USER: 'migration_bot',\n DB_PASSWORD: 'Center2025',\n // Project ID: 1=LCBP3, 2=LCBP3-C1, 3=LCBP3-C2\n PROJECT_ID: 3\n};\n\nreturn [{ json: { config_loaded: true, timestamp: new Date().toISOString(), config: CONFIG } }];" }, - "id": "9230401b-51f2-4744-b055-100a883a5bad", + "id": "8f1d3378-cca6-48b6-99db-693e46ac81ef", "name": "Set Configuration", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 14400, - 6800 + 31216, + 13504 ], "notes": "กำหนดค่า Configuration ทั้งหมด - แก้ไขที่นี่ก่อนรัน" }, @@ -83,13 +79,13 @@ "timeout": 10000 } }, - "id": "5142fb05-369a-4b04-b98f-4208b71254c7", + "id": "6c6679b4-85f3-4c2c-ac8e-4281d6ae61f6", "name": "Fetch Categories", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.1, "position": [ - 14816, - 6224 + 31216, + 13696 ], "notes": "ดึง Categories จาก Backend" }, @@ -109,13 +105,13 @@ "timeout": 10000 } }, - "id": "af45bbb3-cf8e-463b-81b6-637bf5defde2", + "id": "98b9159a-f21d-4b33-9524-058a78ccfc93", "name": "Fetch Tags", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.1, "position": [ - 15088, - 6224 + 31392, + 13696 ], "notes": "ดึง Tags ที่มีอยู่แล้วจาก Backend" }, @@ -126,13 +122,13 @@ "timeout": 5000 } }, - "id": "b4b8dd0c-8ed4-4c1c-a70d-c439589d2d81", + "id": "60e81de6-e9b2-4bff-afcc-bef9d5b959b5", "name": "Check Backend Health", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.1, "position": [ - 14576, - 6432 + 31392, + 13504 ], "onError": "continueErrorOutput", "notes": "ตรวจสอบ Backend พร้อมใช้งาน" @@ -141,13 +137,13 @@ "parameters": { "jsCode": "const fs = require('fs');\nconst config = $('Set Configuration').first().json.config;\n\n// Check file mount and inputs\ntry {\n if (!fs.existsSync(config.EXCEL_FILE)) {\n throw new Error(`Excel file not found at: ${config.EXCEL_FILE}`);\n }\n if (!fs.existsSync(config.SOURCE_PDF_DIR)) {\n throw new Error(`PDF Source directory not found at: ${config.SOURCE_PDF_DIR}`);\n }\n \n const files = fs.readdirSync(config.SOURCE_PDF_DIR);\n \n // Check write permission to log path\n fs.writeFileSync(`${config.LOG_PATH}/.preflight_ok`, new Date().toISOString());\n \n // Grab categories out of the previous node (Fetch Categories) if available\n // otherwise use fallback array\n let categories = ['Correspondence','RFA','Drawing','Transmittal','Report','Other'];\n try {\n const upstreamData = $('Fetch Categories').first()?.json?.data;\n if (upstreamData && Array.isArray(upstreamData)) {\n categories = upstreamData.map(c => c.name || c.type || c); // very loose mapping depending on API response\n }\n } catch(e) {}\n \n // Grab existing tags from Fetch Tags node\n let existingTags = [];\n try {\n const tagData = $('Fetch Tags').first()?.json?.data || [];\n existingTags = Array.isArray(tagData) ? tagData.map(t => t.tag_name || t.name || '').filter(Boolean) : [];\n } catch(e) {}\n \n return [{ json: { \n preflight_ok: true, \n pdf_count_in_source: files.length,\n excel_target: config.EXCEL_FILE,\n system_categories: categories,\n existing_tags: existingTags,\n timestamp: new Date().toISOString()\n }}];\n} catch (err) {\n throw new Error(`Pre-flight check failed: ${err.message}`);\n}" }, - "id": "95cddf96-a761-479b-b5fc-78ec7765d0c6", + "id": "910b13e2-994a-4fb6-bca1-637e1628c586", "name": "File Mount Check", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 14912, - 6528 + 31216, + 13904 ], "notes": "ตรวจสอบ File System มีไฟล์ Excel และ Folder ตามตั้งค่า" }, @@ -157,13 +153,13 @@ "query": "SELECT last_processed_index, status FROM migration_progress WHERE batch_id = '{{$('Set Configuration').first().json.config.BATCH_ID}}' LIMIT 1", "options": {} }, - "id": "3456794f-f91a-42ae-91e6-3619e5cbbfcb", + "id": "a83f8598-72fd-4cc8-9d98-1ea3cb3b42df", "name": "Read Checkpoint", "type": "n8n-nodes-base.mySql", "typeVersion": 2.4, "position": [ - 15120, - 6768 + 31632, + 13744 ], "alwaysOutputData": true, "credentials": { @@ -180,13 +176,13 @@ "fileSelector": "={{ $json.excel_target }}", "options": {} }, - "id": "25329cd6-0bd2-4391-8680-20eaa32c817b", + "id": "063bcef1-791a-4923-a659-8b9a0ba3e336", "name": "Read Excel Binary", "type": "n8n-nodes-base.readWriteFile", "typeVersion": 1, "position": [ - 14608, - 7216 + 31392, + 13904 ], "notes": "ดึงไฟล์ Excel ขึ้นมาไว้ในหน่วยความจำ" }, @@ -194,13 +190,13 @@ "parameters": { "options": {} }, - "id": "85a6561d-4b7b-454a-aba9-18b612b5abfb", + "id": "e07efdde-b9b1-402a-ba01-44175982749b", "name": "Read Excel", "type": "n8n-nodes-base.spreadsheetFile", "typeVersion": 2, "position": [ - 14784, - 6944 + 31392, + 14112 ], "notes": "แปลงข้อมูล Excel เป็น JSON Data" }, @@ -208,13 +204,13 @@ "parameters": { "jsCode": "const cpJson = $input.first()?.json || {};\nconst startIndex = cpJson.last_processed_index || 0;\nconst config = $('Set Configuration').first().json.config;\n\nconst allItems = $('Read Excel').all().map(i => i.json);\nconst remaining = allItems.slice(startIndex);\nconst currentBatch = remaining.slice(0, config.BATCH_SIZE);\n\n// Encoding Normalization\nconst normalize = (str) => {\n if (!str) return '';\n return String(str).normalize('NFC').trim();\n};\n\nreturn currentBatch.map((item, i) => {\n // Safe getter to handle whitespace or case in Excel column names\n const getVal = (possibleKeys) => {\n const exactMatch = possibleKeys.find(k => item[k] !== undefined);\n if (exactMatch) return item[exactMatch];\n \n // Fallback: Check lowercase/trimmed keys if exact match fails\n const lowerTrimmedKeys = Object.keys(item).map(k => ({ original: k, parsed: k.toLowerCase().trim() }));\n for (const pk of possibleKeys) {\n const found = lowerTrimmedKeys.find(k => k.parsed === pk.toLowerCase().trim());\n if (found) return item[found.original];\n }\n return '';\n };\n\n const docNum = getVal(['document_number', 'correspondence_number', 'Document Number', 'Corr. No.']);\n const excelFileName = getVal(['File name', 'file_name', 'File Name', 'filename']);\n \n if (!excelFileName) {\n throw new Error(`Missing 'File name' column for row ${i + startIndex + 1}, document: ${docNum}`);\n }\n \n return {\n json: {\n document_number: normalize(docNum),\n title: normalize(getVal(['title', 'Title', 'Subject', 'subject'])),\n legacy_number: normalize(getVal(['legacy_number', 'Legacy Number', 'Response Doc.'])),\n excel_revision: getVal(['revision', 'Revision', 'rev']) || 1,\n original_index: startIndex + i,\n batch_id: config.BATCH_ID,\n file_name: normalize(excelFileName),\n issued_date: normalize(getVal(['issued_date', 'Issued_date', 'Issued Date', 'date', 'Date', 'document_date', 'Document_Date'])),\n received_date: normalize(getVal(['received_date', 'Received_date', 'Received Date', 'receive', 'Receive'])),\n correspondence_type: normalize(getVal(['correspondence_types', 'correspondence_type', 'Correspondence Types', 'Correspondence Type'])),\n sender: normalize(getVal(['sender', 'Sender', 'from', 'From'])),\n receiver: normalize(getVal(['receiver', 'Receiver', 'to', 'To'])),\n project_code: normalize(getVal(['project_code', 'Project Code', 'project', 'Project'])),\n _raw_excel_keys: Object.keys(item),\n _raw_excel: item\n }\n };\n});" }, - "id": "a119287e-2cdd-4cb0-9c3e-c07648c732ef", + "id": "80845e32-c283-4e9f-af73-6339d675fb38", "name": "Process Batch + Encoding", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 15280, - 6464 + 31808, + 13488 ], "alwaysOutputData": true, "notes": "ตัด Batch + Normalize UTF-8" @@ -223,13 +219,13 @@ "parameters": { "jsCode": "const fs = require('fs');\nconst path = require('path');\nconst config = $('Set Configuration').first().json.config;\n\nconst items = $input.all();\nif (!items || items.length === 0) return [];\n\nconst validated = [];\nconst errors = [];\n\nfor (const item of items) {\n const fileName = item.json?.file_name;\n if (!fileName) {\n errors.push({\n ...item,\n json: { ...item.json, file_valid: false, error: 'file_name is missing', error_type: 'MISSING_FILENAME', file_exists: false }\n });\n continue;\n }\n \n // Use file name from Excel directly, add .pdf if missing\n let safeName = path.basename(String(fileName)).normalize('NFC');\n if (!safeName.toLowerCase().endsWith('.pdf')) {\n safeName += '.pdf';\n }\n const filePath = path.resolve(config.SOURCE_PDF_DIR, safeName);\n \n // Path traversal check\n if (!filePath.startsWith(path.resolve(config.SOURCE_PDF_DIR))) {\n errors.push({\n ...item,\n json: { ...item.json, file_valid: false, error: 'Path traversal detected', error_type: 'SECURITY', file_exists: false }\n });\n continue;\n }\n \n try {\n if (fs.existsSync(filePath)) {\n const stats = fs.statSync(filePath);\n validated.push({\n ...item,\n json: { ...item.json, file_valid: true, file_exists: true, file_size: stats.size, file_path: filePath }\n });\n } else {\n errors.push({\n ...item,\n json: { ...item.json, file_valid: false, error: `File not found: ${safeName}`, error_type: 'FILE_NOT_FOUND', file_exists: false }\n });\n }\n } catch (err) {\n errors.push({\n ...item,\n json: { ...item.json, file_valid: false, error: err.message, error_type: 'FILE_ERROR', file_exists: false }\n });\n }\n}\n\nreturn [...validated, ...errors];" }, - "id": "afba94df-aa7a-49a2-9cd0-c45dae863adf", + "id": "2183d687-4708-4d77-a0a9-13ccf29baf69", "name": "File Validator", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 15472, - 6368 + 31984, + 13488 ], "notes": "ตรวจสอบไฟล์ PDF ตัวชี้ใน Directory จาก Config" }, @@ -239,13 +235,13 @@ "query": "SELECT is_fallback_active, recent_error_count FROM migration_fallback_state WHERE batch_id = '{{$('Set Configuration').first().json.config.BATCH_ID}}' LIMIT 1", "options": {} }, - "id": "5f37b586-a782-405e-94c5-15c8d0be83cd", + "id": "8b0c61d0-96e4-468a-991f-a40e534e167a", "name": "Check Fallback State", "type": "n8n-nodes-base.mySql", "typeVersion": 2.4, "position": [ - 16112, - 6400 + 31792, + 13888 ], "alwaysOutputData": true, "credentials": { @@ -261,13 +257,13 @@ "parameters": { "jsCode": "const config = $('Set Configuration').first().json.config;\nconst fallbackState = $('Check Fallback State').first()?.json || { is_fallback_active: false, recent_error_count: 0 };\nconst isFallback = fallbackState.is_fallback_active || false;\nconst model = isFallback ? config.OLLAMA_MODEL_FALLBACK : config.OLLAMA_MODEL_PRIMARY;\n\n// Read DB Context\nconst dbContext = $('Fetch DB Context').all().map(i => i.json);\nconst dbProjects = dbContext.filter(d => d.type === 'projects').map(d => ({id: d.id, code: d.text1, name: d.text2}));\nconst dbDisciplines = dbContext.filter(d => d.type === 'disciplines').map(d => ({id: d.id, th: d.text1, en: d.text2}));\nconst dbOrgs = dbContext.filter(d => d.type === 'organizations').map(d => ({id: d.id, name: d.text1, code: d.text2}));\nconst dbTags = dbContext.filter(d => d.type === 'tags').map(d => ({id: d.id, name: d.text1}));\nconst dbCorrTypes = dbContext.filter(d => d.type === 'correspondence_types').map(d => ({id: d.id, code: d.text1, name: d.text2}));\n\nlet systemCategories = ['Correspondence','RFA','Drawing','Transmittal','Report','Other'];\ntry { systemCategories = $('File Mount Check').first().json.system_categories || systemCategories; } catch (e) {}\n\nconst pdfItems = $('Extract PDF Text').all();\n// File Validator passes all original Excel JSON fields through (sender, receiver, project_code, etc.)\n// Read PDF File overwrites the JSON with binary data, so we must go back one step\nconst metaItems = $('File Validator').all();\n\nreturn pdfItems.map((pdfItem, i) => {\n const item = metaItems[i] || pdfItem;\n\n const docNum = String(item.json.document_number || '');\n const title = String(item.json.title || '');\n const legacyNum = String(item.json.legacy_number || '');\n const issuedDate = String(item.json.issued_date || '');\n const receivedDate = String(item.json.received_date || '');\n const corrType = String(item.json.correspondence_type || '');\n const senderCode = String(item.json.sender || '');\n const receiverCode = String(item.json.receiver || '');\n const projectCode = String(item.json.project_code || '');\n\n // JavaScript pre-mapping\n const findOrgId = (code) => {\n if (!code) return null;\n const match = dbOrgs.find(o => o.code === code || o.name === code);\n return match ? match.id : null;\n };\n\n const findProjectId = (code) => {\n if (!code) return config.PROJECT_ID; // Fallback to config\n const match = dbProjects.find(p => p.code === code || p.name === code);\n return match ? match.id : config.PROJECT_ID;\n };\n\n const senderId = findOrgId(senderCode);\n const receiverId = findOrgId(receiverCode);\n const projectId = findProjectId(projectCode);\n // Excel corrType is likely already the ID based on requirements, but fallback matching to ID if needed\n const corrMatch = dbCorrTypes.find(c => String(c.id) === corrType || c.code === corrType || c.name === corrType);\n const corrTypeId = corrMatch ? corrMatch.id : (isNaN(parseInt(corrType)) ? null : parseInt(corrType));\n\n const isRFA = docNum.includes('-RFA-') || title.toLowerCase().includes('rfa');\n\n const systemPrompt = `You are an expert Document Controller for a construction project (LCBP3) in Thailand.\nThe documents are primarily in THAI and ENGLISH.\nYour task is to classify documents and extract metadata from OCR text.\nRespond ONLY with valid JSON.`;\n\n // Use pdfItem for the OCR extracted data, NOT the metaItem\n const pdfText = String(pdfItem.json.data || '').substring(0, 3500).replace(/[^a-zA-Z0-9ก-๙\\s\\.\\/\\-:\\[\\]\\(\\)]/g, ' ');\n\n const userPrompt = `Analyze this document:\n[EXCEL METADATA]\nDocument Number: ${docNum || 'Not provided'}\nTitle: ${title || 'Not provided'}\nIssued Date: ${issuedDate || 'Not provided'}\nReceived Date: ${receivedDate || 'Not provided'}\n\n[DATABASE REFERENCES]\nDisciplines: ${JSON.stringify(dbDisciplines)}\nTags: ${JSON.stringify(dbTags)}\n\n[OCR TEXT EXTRACTION]\n${pdfText}\n\nRules:\n1. Category: Must be one of ${JSON.stringify(systemCategories)}. If Document Number contains \"-RFA-\", category MUST be \"RFA\".\n2. Respond with EXACTLY 8 fields in JSON format:\n - \"discipline_id\": Find 'id' from Disciplines array analyzing text to match 'th' or 'en'. If no match, use ID=64 (from contract LCBP3-C2).\n - \"subject\": Document subject. If OCR is close to EXCEL METADATA Title, use EXCEL METADATA.\n - \"issued_date\": Verify from OCR text if it matches ${issuedDate}, format YYYY-MM-DD.\n - \"received_date\": Verify from OCR text. If empty, default to issued_date.\n - \"status\": Extract status (e.g., For Information, Approve, Reject, Resubmit). This will be exported as \"remark\".\n - \"summary\": 4-5 lines of Thai summary from OCR. This will be exported as \"body\".\n - \"tags\": REQUIRED. Identify 2-5 main topics/themes from the document (from Title, subject matter, and OCR text). For each topic, return an object with:\n * \"tag_name\": short topic name in Thai (2-5 words), e.g. \"คอนกรีตผสม\", \"ทดสอบวัสดุ\"\n * \"description\": one sentence in Thai describing this topic (use key point details). e.g. \"การทดสอบค่า slump ของคอนกรีตผสมที่หน้างาน\"\n Return as: [{\"tag_name\": \"...\", \"description\": \"...\"}, ...]\n - \"key_points\": Array of 3-5 string key points extracted from the document (in Thai).\n\n3. IMPORTANT: You MUST REPLACE the 'null' values in the template below with the actual Integer IDs or text you found. DO NOT reply with literal 'null' if you found a match!\n\nRespond ONLY with this EXACT JSON structure:\n{\n \"discipline_id\": 64,\n \"subject\": \"${title}\",\n \"issued_date\": \"${issuedDate}\",\n \"received_date\": \"${receivedDate || issuedDate}\",\n \"status\": null,\n \"summary\": \"สรุปเนื้อหา 4-5 บรรทัด...\",\n \"tags\": [{\"tag_name\": \"ชื่อหัวข้อ\", \"description\": \"คำอธิบาย key point ของหัวข้อนี้\"}],\n \"key_points\": [\"จุดสำคัญที่ 1\", \"จุดสำคัญที่ 2\", \"จุดสำคัญที่ 3\"],\n \"category\": \"${isRFA ? 'RFA' : 'Correspondence'}\",\n \"confidence\": 0.95\n}`;\n\n return {\n json: {\n ...item.json,\n active_model: model,\n is_fallback: isFallback,\n system_categories: systemCategories,\n pre_mapped: {\n project_id: projectId,\n sender_id: senderId,\n receiver_id: receiverId,\n correspondence_type_id: corrTypeId\n },\n _debug_mapping: {\n excel_project_code: projectCode,\n excel_sender: senderCode,\n excel_receiver: receiverCode,\n excel_corr_type: corrType,\n matched_project: dbProjects.find(p => p.code === projectCode || p.name === projectCode) || null,\n first_org_sample: dbOrgs[0] || null\n },\n ollama_payload: {\n model: model,\n prompt: `${systemPrompt}\\n\\n${userPrompt}`,\n stream: false,\n format: 'json',\n options: {\n temperature: 0.1,\n num_ctx: 8192\n }\n }\n }\n };\n});\n" }, - "id": "249eaae6-95ce-4a19-a073-8528b3e8b322", + "id": "2ba75d42-1de3-4846-a1a3-39d580e7d764", "name": "Build AI Prompt", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 15616, - 6800 + 32144, + 13872 ], "notes": "สร้าง Prompt โดยใช้ Categories จาก System" }, @@ -282,13 +278,13 @@ "timeout": 120000 } }, - "id": "d0939bce-19de-47fe-98e6-84b729737ed8", + "id": "3e8b33cb-8f8f-4d2e-b4cb-9d68cc54d96e", "name": "Ollama AI Analysis", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.1, "position": [ - 15808, - 6800 + 31792, + 14096 ], "notes": "เรียก Ollama วิเคราะห์เอกสาร" }, @@ -296,13 +292,13 @@ "parameters": { "jsCode": "const ollamaItems = $input.all();\nconst originalItems = $('Build AI Prompt').all();\nconst results = [];\n\n// Map AI category names → correspondence_types.type_code in DB\nconst CATEGORY_TO_TYPE_CODE = {\n 'Correspondence': 'LETTER',\n 'RFA': 'RFA',\n 'Transmittal': 'TRANSMITTAL',\n 'Drawing': 'OTHER',\n 'Report': 'OTHER',\n 'Other': 'OTHER',\n};\n\nfor (let i = 0; i < ollamaItems.length; i++) {\n const ollamaItem = ollamaItems[i];\n const originalItem = originalItems[i];\n if (!originalItem) continue;\n const baseJson = originalItem.json;\n\n try {\n let raw = ollamaItem.json.response || '';\n raw = raw.replace(/`{3}json/gi, '').replace(/`{3}/g, '').trim();\n if (!raw) throw new Error('Empty response from AI');\n\n const result = JSON.parse(raw);\n\n // Map AI result to database fields\n let tags = Array.isArray(result.tags) ? result.tags : [];\n\n // Enum Validation for Category\n const systemCategories = baseJson.system_categories || [];\n let finalCategory = result.category;\n if (!systemCategories.includes(finalCategory)) {\n finalCategory = String(baseJson.document_number || '').includes('-RFA-') ? 'RFA' : 'Correspondence';\n }\n\n // Map to type_code for Backend API\n const typeCode = CATEGORY_TO_TYPE_CODE[finalCategory] || 'LETTER';\n\n const preMapped = baseJson.pre_mapped || {};\n\n results.push({\n json: {\n ...baseJson,\n ai_result: {\n suggested_category: finalCategory,\n type_code: typeCode,\n confidence: result.confidence || 0.8,\n project_id: preMapped.project_id || null,\n discipline_id: result.discipline_id || 64,\n sender_id: preMapped.sender_id || null,\n receiver_id: preMapped.receiver_id || null,\n correspondence_type_id: preMapped.correspondence_type_id || null,\n subject: result.subject || baseJson.title,\n issued_date: result.issued_date || baseJson.issued_date,\n received_date: result.received_date || baseJson.received_date || result.issued_date || baseJson.issued_date,\n remark: result.status,\n body: result.summary,\n tags: tags,\n key_points: result.key_points || []\n },\n parse_error: null\n }\n });\n } catch (err) {\n results.push({\n json: {\n ...baseJson,\n ai_result: null,\n parse_error: err.message,\n raw_ai_response: ollamaItem.json.response,\n error_type: 'AI_PARSE_ERROR'\n }\n });\n }\n}\nreturn results;" }, - "id": "37a976fe-34f3-43bd-967a-90261365e451", + "id": "6716162f-1129-4552-a05f-a08ac115fe10", "name": "Parse & Validate AI Response", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 16000, - 6800 + 32000, + 14096 ], "notes": "Parse JSON + Validate Schema + Enum Check" }, @@ -312,13 +308,13 @@ "query": "INSERT INTO migration_fallback_state (batch_id, recent_error_count, is_fallback_active) VALUES ('{{$('Set Configuration').first().json.config.BATCH_ID}}', 1, FALSE) ON DUPLICATE KEY UPDATE recent_error_count = recent_error_count + 1, is_fallback_active = CASE WHEN recent_error_count + 1 >= {{$('Set Configuration').first().json.config.FALLBACK_THRESHOLD}} THEN TRUE ELSE is_fallback_active END, updated_at = NOW()", "options": {} }, - "id": "35eee4ab-a775-4c44-837e-e5e8ca31e104", + "id": "b2ac9722-f917-42fd-81e9-c77e84b84104", "name": "Update Fallback State", "type": "n8n-nodes-base.mySql", "typeVersion": 2.4, "position": [ - 16208, - 6992 + 32464, + 13472 ], "credentials": { "mySql": { @@ -332,13 +328,13 @@ "parameters": { "jsCode": "const config = $('Set Configuration').first().json.config;\nconst items = $('Parse & Validate AI Response').all();\n\nconst results = [];\n\nfor (const item of items) {\n const data = item.json;\n \n // Base structure ensuring we keep all existing data\n let resultItem = { json: { ...data } };\n \n // Handle Parse Errors from upstream\n if (data.parse_error || !data.ai_result) {\n resultItem.json.route_index = 3;\n results.push(resultItem);\n continue;\n }\n \n const ai = data.ai_result;\n \n // Revision Drift Protection\n if (data.current_db_revision !== undefined) {\n const expectedRev = data.current_db_revision + 1;\n if (parseInt(data.excel_revision) !== expectedRev) {\n resultItem.json.review_reason = `Revision drift: Excel=${data.excel_revision}, Expected=${expectedRev}`;\n resultItem.json.route_index = 1;\n results.push(resultItem);\n continue;\n }\n }\n \n // Confidence Routing\n if (ai.confidence >= config.CONFIDENCE_HIGH) {\n resultItem.json.route_index = 0;\n } else if (ai.confidence >= config.CONFIDENCE_LOW) {\n resultItem.json.review_reason = `Confidence ${ai.confidence.toFixed(2)} < ${config.CONFIDENCE_HIGH}`;\n resultItem.json.route_index = 1;\n } else {\n resultItem.json.reject_reason = ai.is_valid === false ? 'AI marked invalid' : `Confidence ${ai.confidence.toFixed(2)} < ${config.CONFIDENCE_LOW}`;\n resultItem.json.route_index = 2;\n }\n results.push(resultItem);\n}\n\nreturn results;" }, - "id": "90afb155-bf51-48dd-8046-22661351e15f", + "id": "ccaaee30-ead6-46c0-954a-eb8b98620cb3", "name": "Confidence Router", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 16208, - 6800 + 32160, + 14096 ], "notes": "แยกตาม Confidence: Auto(≥0.85) / Review(≥0.60) / Reject(<0.60)" }, @@ -366,43 +362,43 @@ "timeout": 30000 } }, - "id": "d2368dca-715b-4aa7-9b30-bdafad53868c", + "id": "4d0260de-6877-4997-8af6-8dd1becde246", "name": "Import to Backend", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.1, "position": [ - 16600, - 6592 + 32704, + 13664 ], "notes": "ส่งข้อมูลเข้า LCBP3 Backend พร้อม Idempotency-Key" }, { "parameters": { - "jsCode": "// $input here is the HTTP response from Import to Backend — it has no original_index.\n// We must go back to Build Import Payload which preserved the original item data.\nconst originalData = $('Build Import Payload').first().json;\nconst importResponse = $input.first().json;\n\nconst idx = originalData.original_index ?? 0;\nconst shouldCheckpoint = idx % 10 === 0;\n\nreturn [{\n json: {\n ...originalData,\n import_response: importResponse,\n should_update_checkpoint: shouldCheckpoint,\n checkpoint_index: idx,\n import_status: 'success',\n timestamp: new Date().toISOString()\n }\n}];" + "jsCode": "// $input here is the HTTP response from Import to Backend — it has no original_index.\n// We must go back to Build Import Payload which preserved the original item data.\nconst items = $input.all();\nconst originalItems = $('Build Import Payload').all();\n\nreturn items.map((item, i) => {\n const originalData = originalItems[i]?.json || item.json;\n const idx = originalData.original_index ?? 0;\n const shouldCheckpoint = idx % 10 === 0;\n\n return {\n json: {\n ...originalData,\n import_response: item.json,\n should_update_checkpoint: shouldCheckpoint,\n checkpoint_index: idx,\n import_status: 'success',\n timestamp: new Date().toISOString()\n }\n };\n});\n" }, - "id": "1ae2b021-7ad6-46aa-855c-cceaecef7abf", + "id": "929ebc49-1a4a-4d17-86b7-570bbb00dd53", "name": "Flag Checkpoint", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 16608, - 6592 + 32880, + 13664 ], "notes": "กำหนดว่าจะบันทึก Checkpoint หรือไม่ (ทุก 10 records)" }, { "parameters": { "operation": "executeQuery", - "query": "INSERT INTO migration_progress (batch_id, last_processed_index, status) VALUES ('{{$('Set Configuration').first().json.config.BATCH_ID}}', {{$json.checkpoint_index}}, 'RUNNING') ON DUPLICATE KEY UPDATE last_processed_index = {{$json.checkpoint_index}}, updated_at = NOW()", + "query": "INSERT INTO migration_progress (batch_id, last_processed_index, status) VALUES ('{{$('Set Configuration').first().json.config.BATCH_ID}}', {{$json.checkpoint_index || 0}}, 'RUNNING') ON DUPLICATE KEY UPDATE last_processed_index = {{$json.checkpoint_index || 0}}, updated_at = NOW()", "options": {} }, - "id": "860a6954-fee8-44d6-8cc0-05a00ea19ba0", + "id": "bb0e611b-db28-4266-ba40-3b5d534a16f7", "name": "Save Checkpoint", "type": "n8n-nodes-base.mySql", "typeVersion": 2.4, "position": [ - 17200, - 6592 + 32928, + 13856 ], "credentials": { "mySql": { @@ -418,13 +414,13 @@ "query": "INSERT INTO migration_review_queue (document_number, title, original_title, ai_suggested_category, ai_confidence, ai_issues, review_reason, status, created_at) VALUES ('{{$json.document_number}}', '{{$json.ai_result.subject || $json.title}}', '{{$json.title}}', '{{$json.ai_result.suggested_category}}', {{$json.ai_result.confidence}}, '{{JSON.stringify({ key_points: $json.ai_result.key_points || [], source_file_path: $json.pdf_path, raw: $json.ai_result, sender_id: $json.ai_result.sender_org_id, discipline_id: $json.ai_result.discipline_id, document_date: $json.ai_result.document_date, issued_date: $json.ai_result.issued_date, received_date: $json.ai_result.received_date, tags: $json.ai_result.suggested_tags })}}', '{{$json.review_reason}}', 'PENDING', NOW()) ON DUPLICATE KEY UPDATE status = 'PENDING', review_reason = '{{$json.review_reason}}', ai_issues = '{{JSON.stringify({ key_points: $json.ai_result.key_points || [], source_file_path: $json.pdf_path, raw: $json.ai_result, sender_id: $json.ai_result.sender_org_id, discipline_id: $json.ai_result.discipline_id, document_date: $json.ai_result.document_date, issued_date: $json.ai_result.issued_date, received_date: $json.ai_result.received_date, tags: $json.ai_result.suggested_tags })}}', created_at = NOW()", "options": {} }, - "id": "d76e9be2-9cc9-4b18-96de-637cbef9e90a", + "id": "c1bd4485-e58f-4270-892e-edda34c2e328", "name": "Insert Review Queue", "type": "n8n-nodes-base.mySql", "typeVersion": 2.4, "position": [ - 16400, - 6800 + 32896, + 14016 ], "credentials": { "mySql": { @@ -438,13 +434,13 @@ "parameters": { "jsCode": "const fs = require('fs');\nconst item = $input.first();\nconst config = $('Set Configuration').first().json.config;\n\nconst csvPath = `${config.LOG_PATH}/reject_log.csv`;\nconst header = 'timestamp,document_number,title,reject_reason,ai_confidence,key_points\\n';\nconst esc = (s) => `\"${String(s || '').replace(/\"/g, '\"\"')}\"`;\n\nif (!fs.existsSync(csvPath)) {\n fs.writeFileSync(csvPath, header, 'utf8');\n}\n\nconst line = [\n new Date().toISOString(),\n esc(item.json.document_number),\n esc(item.json.title),\n esc(item.json.reject_reason),\n item.json.ai_result?.confidence ?? 'N/A',\n esc(JSON.stringify(item.json.ai_result?.key_points || []))\n].join(',') + '\\n';\n\nfs.appendFileSync(csvPath, line, 'utf8');\n\nreturn [$input.first()];" }, - "id": "70ff9ff0-b5f8-4d10-baf5-1840c5b0fd24", + "id": "0bb3530f-02d5-44d0-ad94-c94d97d91b6a", "name": "Log Reject to CSV", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 16400, - 6992 + 32624, + 14032 ], "notes": "บันทึกรายการที่ถูกปฏิเสธลง CSV" }, @@ -452,13 +448,13 @@ "parameters": { "jsCode": "const fs = require('fs');\nconst items = $input.all();\nconst config = $('Set Configuration').first().json.config;\n\nconst csvPath = `${config.LOG_PATH}/error_log.csv`;\nconst header = 'timestamp,document_number,error_type,error_message,raw_ai_response\\n';\nconst esc = (s) => `\"${String(s || '').replace(/\"/g, '\"\"')}\"`;\n\nif (!fs.existsSync(csvPath)) {\n fs.writeFileSync(csvPath, header, 'utf8');\n}\n\nfor (const item of items) {\n const line = [\n new Date().toISOString(),\n esc(item.json.document_number),\n esc(item.json.error_type || 'UNKNOWN'),\n esc(item.json.error || item.json.parse_error),\n esc(item.json.raw_ai_response || '')\n ].join(',') + '\\n';\n \n fs.appendFileSync(csvPath, line, 'utf8');\n}\n\nreturn items;" }, - "id": "cc7b60df-8342-4ffd-ac56-23a101f0719e", + "id": "8250dd88-ca81-45aa-93d8-480c9bcd6b14", "name": "Log Error to CSV", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 15600, - 7200 + 32448, + 14128 ], "notes": "บันทึก Error ลง CSV (จาก File Validator)" }, @@ -468,13 +464,13 @@ "query": "INSERT INTO migration_errors (batch_id, document_number, error_type, error_message, raw_ai_response, created_at) VALUES ('{{$('Set Configuration').first().json.config.BATCH_ID}}', '{{$json.document_number}}', '{{$json.error_type || \"UNKNOWN\"}}', '{{$json.error || $json.parse_error}}', '{{$json.raw_ai_response || \"\"}}', NOW())", "options": {} }, - "id": "443631b9-5bf3-4803-9cab-3348bc1f74d9", + "id": "0f058ad0-3c09-4c9f-bdcf-503cd58ee395", "name": "Log Error to DB", "type": "n8n-nodes-base.mySql", "typeVersion": 2.4, "position": [ - 16208, - 7200 + 32752, + 14128 ], "credentials": { "mySql": { @@ -486,16 +482,16 @@ }, { "parameters": { - "amount": "={{$('Set Configuration').first().json.config.DELAY_MS}}", - "unit": "milliseconds" + "amount": "={{$('Set Configuration').first().json.config.DELAY_MS / 1000}}", + "unit": "seconds" }, - "id": "b5c9373b-d617-48fd-8ab5-1c7933dd49fe", + "id": "07c1c5d5-5ffc-4e3d-ab3e-4b62ad079388", "name": "Delay", "type": "n8n-nodes-base.wait", "typeVersion": 1, "position": [ - 17400, - 6800 + 33104, + 14080 ], "webhookId": "38e97a99-4dcc-4b63-977a-a02945a1c369", "notes": "หน่วงเวลาระหว่าง Batches" @@ -604,13 +600,13 @@ }, "options": {} }, - "id": "9e7856e3-b487-4410-8062-5c85382a200d", + "id": "65f0bb6c-496a-4409-8b88-3132866cf9a4", "name": "Route by Confidence", "type": "n8n-nodes-base.switch", "typeVersion": 3.2, "position": [ - 16416, - 6800 + 32336, + 13744 ] }, { @@ -618,13 +614,13 @@ "fileSelector": "={{ $json.file_path }}", "options": {} }, - "id": "68d17f1c-81d8-4294-ae8f-88b14833dd84", + "id": "4fd3133e-39e1-4860-95c7-3e87ee43ed51", "name": "Read PDF File", "type": "n8n-nodes-base.readWriteFile", "typeVersion": 1, "position": [ - 15760, - 6128 + 31824, + 13680 ], "onError": "continueErrorOutput" }, @@ -661,15 +657,17 @@ "sendBody": true, "contentType": "binaryData", "inputDataFieldName": "data", - "options": {} + "options": { + "timeout": 600000 + } }, - "id": "1da911ca-3796-4b60-b323-a541604330d5", + "id": "2d3868e0-ed56-4921-8d68-bf7b69a64546", "name": "Extract PDF Text", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ - 16096, - 6128 + 32096, + 13664 ], "onError": "continueErrorOutput" }, @@ -679,13 +677,13 @@ "query": "SELECT 'projects' as type, id, project_code as text1, project_name as text2 FROM projects\nUNION ALL\nSELECT 'disciplines' as type, id, code_name_th as text1, code_name_en as text2 FROM disciplines\nUNION ALL\nSELECT 'organizations' as type, id, organization_name as text1, organization_code as text2 FROM organizations\nUNION ALL\nSELECT 'tags' as type, id, tag_name as text1, description as text2 FROM tags\nUNION ALL\nSELECT 'correspondence_types' as type, id, type_code as text1, type_name as text2 FROM correspondence_types", "options": {} }, - "id": "0ef2fc07-af6d-4a2a-aa2b-2b563afb2c6d", + "id": "2e31dc54-3d57-4c88-9d35-1aba0132cdf9", "name": "Fetch DB Context", "type": "n8n-nodes-base.mySql", "typeVersion": 2.4, "position": [ - 15616, - 6592 + 32000, + 13872 ], "alwaysOutputData": true, "credentials": { @@ -697,46 +695,46 @@ "notes": "ดึงข้อมูลจาก Database ส่งให้ AI" }, { - "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "parameters": { + "jsCode": "const items = $input.all();\nconst config = $('Set Configuration').first().json.config;\n\nreturn items.map(item => {\n const ai = item.json.ai_result || {};\n\n let subjectStr = String(ai.subject || item.json.title || 'ไม่มีชื่อเรื่อง');\n let categoryCode = ai.type_code || 'LETTER';\n\n if (subjectStr.includes('ขออนุมัติ')) {\n categoryCode = 'RFA';\n }\n\n let remarkStr = ai.remark || '';\n if (item.json.legacy_number) {\n remarkStr = (`Legacy Number: ${item.json.legacy_number}\\n` + remarkStr).trim();\n }\n\n return {\n json: {\n ...item.json,\n import_payload: {\n document_number: String(item.json.document_number || ''),\n subject: subjectStr,\n category: categoryCode,\n source_file_path: item.json.file_path || '/dev/null',\n ai_confidence: ai.confidence || 0.8,\n migrated_by: 'SYSTEM_IMPORT',\n batch_id: config.BATCH_ID,\n project_id: Number(ai.project_id || config.PROJECT_ID),\n discipline_id: ai.discipline_id || null,\n sender_id: ai.sender_id || null,\n receiver_id: ai.receiver_id || null,\n document_date: ai.issued_date || '',\n issued_date: ai.issued_date || '',\n received_date: ai.received_date || '',\n body: ai.body || '',\n details: {\n legacy_number: item.json.legacy_number || '',\n remark: remarkStr,\n key_points: ai.key_points || [],\n tags: ai.tags || []\n }\n }\n }\n };\n});\n" + }, + "id": "57421305-8c7e-4fa4-a339-1144902cae22", "name": "Build Import Payload", "typeVersion": 2, - "parameters": { - "jsCode": "const item = $input.first();\nconst config = $('Set Configuration').first().json.config;\nconst ai = item.json.ai_result || {};\n\nlet subjectStr = String(ai.subject || item.json.title || 'ไม่มีชื่อเรื่อง');\nlet categoryCode = ai.type_code || 'LETTER';\n\nif (subjectStr.includes('ขออนุมัติ')) {\n categoryCode = 'RFA';\n}\n\nlet remarkStr = ai.remark || '';\nif (item.json.legacy_number) {\n remarkStr = (`Legacy Number: ${item.json.legacy_number}\\n` + remarkStr).trim();\n}\n\nreturn [{\n json: {\n ...item.json,\n import_payload: {\n document_number: String(item.json.document_number || ''),\n subject: subjectStr,\n category: categoryCode,\n source_file_path: item.json.file_path || '/dev/null',\n ai_confidence: ai.confidence || 0.8,\n migrated_by: 'SYSTEM_IMPORT',\n batch_id: config.BATCH_ID,\n project_id: Number(ai.project_id || config.PROJECT_ID),\n discipline_id: ai.discipline_id || null,\n sender_id: ai.sender_id || null,\n receiver_id: ai.receiver_id || null,\n document_date: ai.issued_date || '',\n issued_date: ai.issued_date || '',\n received_date: ai.received_date || '',\n body: ai.body || '',\n details: {\n legacy_number: item.json.legacy_number || '',\n remark: remarkStr,\n key_points: ai.key_points || [],\n tags: ai.tags || []\n }\n }\n }\n}];" - }, "type": "n8n-nodes-base.code", "position": [ - 16400, - 6592 + 32544, + 13664 ], "notes": "สร้าง payload สำหรับ Import to Backend" }, { - "id": "f1e2d3c4-b5a6-7890-fedc-ba0987654321", + "parameters": { + "jsCode": "const items = $input.all();\nconst config = $('Set Configuration').first().json.config;\n\nconst results = [];\n\nfor (const itemWrapper of items) {\n const item = itemWrapper.json;\n const tags = item.import_payload?.details?.tags || item.ai_result?.tags || [];\n const projectId = item.import_payload?.project_id || item.ai_result?.project_id || config.PROJECT_ID;\n const correspondenceId = item.import_response?.id || item.import_response?.data?.id;\n\n if (!correspondenceId || !Array.isArray(tags) || tags.length === 0) {\n results.push({ json: { ...item, tags_upserted: 0, tag_ids_to_link: [], correspondence_id: correspondenceId } });\n continue;\n }\n\n const tagIds = [];\n const tagResults = [];\n\n for (const tag of tags) {\n if (!tag || !tag.tag_name) continue;\n try {\n const response = await $helpers.httpRequest({\n method: 'POST',\n url: `${config.BACKEND_URL}/api/master/tags`,\n headers: { 'Authorization': config.MIGRATION_TOKEN, 'Content-Type': 'application/json' },\n body: { tag_name: String(tag.tag_name), description: String(tag.description || ''), project_id: Number(projectId), color_code: 'default' },\n json: true\n });\n if (response && response.id) {\n tagIds.push(response.id);\n tagResults.push({ tag_name: tag.tag_name, status: 'ok', id: response.id });\n }\n } catch (e) {\n tagResults.push({ tag_name: tag.tag_name, status: 'error', reason: String(e.message || e) });\n }\n }\n\n results.push({\n json: {\n ...item,\n tags_upserted: tagResults.filter(r => r.status === 'ok').length,\n tag_ids_to_link: tagIds,\n correspondence_id: correspondenceId,\n tags_result: tagResults\n }\n });\n}\n\nreturn results;\n" + }, + "id": "68098411-7576-4341-8537-e557a4013377", "name": "Upsert Tags", "typeVersion": 2, - "parameters": { - "jsCode": "const item = $input.first().json;\nconst config = $('Set Configuration').first().json.config;\nconst tags = item.import_payload?.details?.tags || item.ai_result?.tags || [];\nconst projectId = item.import_payload?.project_id || item.ai_result?.project_id || config.PROJECT_ID;\n\nconst correspondenceId = item.import_response?.id || item.import_response?.data?.id;\n\nif (!correspondenceId || !Array.isArray(tags) || tags.length === 0) {\n return [{ json: { ...item, tags_upserted: 0, tags_linked: 0, tag_ids_to_link: [], correspondence_id: correspondenceId } }];\n}\n\nconst results = [];\nconst tagIds = [];\n\nfor (const tag of tags) {\n if (!tag || !tag.tag_name) continue;\n try {\n const response = await $helpers.httpRequest({\n method: 'POST',\n url: `${config.BACKEND_URL}/api/master/tags`,\n headers: {\n 'Authorization': config.MIGRATION_TOKEN,\n 'Content-Type': 'application/json'\n },\n body: {\n tag_name: String(tag.tag_name),\n description: String(tag.description || ''),\n project_id: Number(projectId),\n color_code: 'default'\n },\n json: true\n });\n \n if (response && response.id) {\n tagIds.push(response.id);\n results.push({ tag_name: tag.tag_name, status: 'ok', id: response.id });\n }\n } catch (e) {\n try {\n const searchRes = await $helpers.httpRequest({\n method: 'GET',\n url: `${config.BACKEND_URL}/api/master/tags?project_id=${projectId}&search=${encodeURIComponent(tag.tag_name)}`,\n headers: {\n 'Authorization': config.MIGRATION_TOKEN\n },\n json: true\n });\n \n const existing = searchRes.data?.find(t => t.tag_name === tag.tag_name);\n if (existing && existing.id) {\n tagIds.push( existing.id );\n results.push({ tag_name: tag.tag_name, status: 'found_existing', id: existing.id });\n } else {\n results.push({ tag_name: tag.tag_name, status: 'error_conflict_not_found', reason: String(e.message || e) });\n }\n } catch(fetchErr) {\n results.push({ tag_name: tag.tag_name, status: 'error_fetching_existing', reason: String(fetchErr.message || fetchErr) });\n }\n }\n}\n\nreturn [{ \n json: { \n ...item, \n tags_upserted: results.filter(r => r.status === 'ok').length,\n tag_ids_to_link: tagIds,\n correspondence_id: correspondenceId,\n tags_result: results\n } \n}];" - }, "type": "n8n-nodes-base.code", "position": [ - 16800, - 6592 + 32592, + 13856 ], "notes": "Upsert tags หลัง import สำเร็จ" }, { - "id": "aaabbbccc-1111-2222-3333-abcdef123456", - "name": "Link Tags to Correspondence", - "typeVersion": 2.4, "parameters": { - "query": "={{ $json.tag_ids_to_link && $json.tag_ids_to_link.length > 0 && $json.correspondence_id ? 'INSERT IGNORE INTO correspondence_tags (correspondence_id, tag_id) VALUES ' + $json.tag_ids_to_link.map(id => '(' + $json.correspondence_id + ', ' + id + ')').join(', ') + ';' : 'SELECT 1;' }}", "operation": "executeQuery", + "query": "{{ $json.tag_ids_to_link && $json.tag_ids_to_link.length > 0 && $json.correspondence_id ? 'INSERT IGNORE INTO correspondence_tags (correspondence_id, tag_id) VALUES ' + $json.tag_ids_to_link.map(id => '(' + $json.correspondence_id + ', ' + id + ')').join(', ') + ';' : 'SELECT 1;' }}", "options": {} }, + "id": "8f998b3b-9463-4d9c-93a7-f8ed27880ba3", + "name": "Link Tags to Correspondence", + "typeVersion": 2.4, "type": "n8n-nodes-base.mySql", "position": [ - 17000, - 6592 + 32768, + 13856 ], "credentials": { "mySql": { @@ -845,6 +843,13 @@ "type": "main", "index": 0 } + ], + [ + { + "node": "Check Backend Health", + "type": "main", + "index": 0 + } ] ] }, @@ -962,9 +967,9 @@ "main": [ [ { - "index": 0, + "node": "Upsert Tags", "type": "main", - "node": "Upsert Tags" + "index": 0 } ] ] @@ -1017,9 +1022,9 @@ "main": [ [ { - "index": 0, + "node": "Build Import Payload", "type": "main", - "node": "Build Import Payload" + "index": 0 } ], [ @@ -1082,9 +1087,9 @@ "main": [ [ { - "index": 0, + "node": "Import to Backend", "type": "main", - "node": "Import to Backend" + "index": 0 } ] ] @@ -1093,9 +1098,9 @@ "main": [ [ { - "index": 0, + "node": "Link Tags to Correspondence", "type": "main", - "node": "Link Tags to Correspondence" + "index": 0 } ] ] @@ -1104,9 +1109,9 @@ "main": [ [ { - "index": 0, + "node": "Save Checkpoint", "type": "main", - "node": "Save Checkpoint" + "index": 0 } ] ] @@ -1117,11 +1122,11 @@ "executionOrder": "v1", "availableInMCP": false }, - "versionId": "2fa84882-2a0d-4394-9af7-5e9e1f0e28d6", + "versionId": "4ec991b8-5e6e-46cd-8177-c5a21f8f6a01", "meta": { "templateCredsSetupCompleted": true, "instanceId": "9e70e47c1eaf3bac72f497ddfbde0983f840f7d0f059537f7e37dd70de18ecb7" }, "id": "u7CLP05AyFb8Um0P", "tags": [] -} \ No newline at end of file +} diff --git a/จัดการตำแหน่ง Node n8n.html b/จัดการตำแหน่ง Node n8n.html new file mode 100644 index 0000000..ef0b3df --- /dev/null +++ b/จัดการตำแหน่ง Node n8n.html @@ -0,0 +1,490 @@ + + +จัดการตำแหน่ง Node n8n
Skip to content

Chat history

+ + + + \ No newline at end of file diff --git a/จัดการตำแหน่ง Node n8n_files/669bbd27-5a06-4b54-862e-cd5b58148bb6.png b/จัดการตำแหน่ง Node n8n_files/669bbd27-5a06-4b54-862e-cd5b58148bb6.png new file mode 100644 index 0000000..cf2425d Binary files /dev/null and b/จัดการตำแหน่ง Node n8n_files/669bbd27-5a06-4b54-862e-cd5b58148bb6.png differ diff --git a/จัดการตำแหน่ง Node n8n_files/ansi-1f6vhsjh.css b/จัดการตำแหน่ง Node n8n_files/ansi-1f6vhsjh.css new file mode 100644 index 0000000..19e7a24 --- /dev/null +++ b/จัดการตำแหน่ง Node n8n_files/ansi-1f6vhsjh.css @@ -0,0 +1 @@ +.ansi-black-fg{color:#000}.ansi-black-bg{background-color:#000}.ansi-red-fg{color:#f66}.ansi-red-bg{background-color:#f66}.ansi-green-fg{color:#94f494}.ansi-green-bg{background-color:#94f494}.ansi-yellow-fg{color:#f4f47b}.ansi-yellow-bg{background-color:#f4f47b}.ansi-blue-fg{color:#9e9eff}.ansi-blue-bg{background-color:#9e9eff}.ansi-magenta-fg{color:#db6bdb}.ansi-magenta-bg{background-color:#db6bdb}.ansi-cyan-fg{color:#81eeee}.ansi-cyan-bg{background-color:#81eeee}.ansi-white-fg{color:#d6d6d6}.ansi-white-bg{background-color:#d6d6d6}.ansi-bright-black-fg{color:#6e6e6e}.ansi-bright-red-fg{color:#ffa8a8}.ansi-bright-green-fg{color:#0f0}.ansi-bright-yellow-fg{color:#ffffa8}.ansi-bright-blue-fg{color:#9494ff}.ansi-bright-magenta-fg{color:#ffb3ff}.ansi-bright-cyan-fg{color:#adffff}.ansi-bright-white-fg{color:#fff} diff --git a/จัดการตำแหน่ง Node n8n_files/api.js.download b/จัดการตำแหน่ง Node n8n_files/api.js.download new file mode 100644 index 0000000..32ed430 --- /dev/null +++ b/จัดการตำแหน่ง Node n8n_files/api.js.download @@ -0,0 +1,33 @@ +(function(){var aa=typeof Object.defineProperties=="function"?Object.defineProperty:function(a,b,c){if(a==Array.prototype||a==Object.prototype)return a;a[b]=c.value;return a},ba=function(a){a=["object"==typeof globalThis&&globalThis,a,"object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global];for(var b=0;b0&&c>0;)if(d[--c]!=b[--e])return!1;return e<=0}});g("Object.is",function(a){return a?a:function(b,c){return b===c?b!==0||1/b===1/c:b!==b&&c!==c}}); +g("Array.prototype.includes",function(a){return a?a:function(b,c){var d=this;d instanceof String&&(d=String(d));var e=d.length;c=c||0;for(c<0&&(c=Math.max(c+e,0));c>>0),da=0,t=function(a){return a};/* + + Copyright Google LLC + SPDX-License-Identifier: Apache-2.0 +*/ +var x={};var y=function(a){if(x!==x)throw Error("Bad secret");this.l=a};y.prototype.toString=function(){return this.l};new y("about:blank");new y("about:invalid#zClosurez");var A=[],D=function(a){console.warn("A URL with content '"+a+"' was sanitized away.")};A.indexOf(D)===-1&&A.push(D);/* + gapi.loader.OBJECT_CREATE_TEST_OVERRIDE &&*/ +var E=window,F=document,ea=E.location,fa=function(){},ha=/\[native code\]/,H=function(a,b,c){return a[b]=a[b]||c},ia=function(a){a=a.sort();for(var b=[],c=void 0,d=0;d0&&(b=ma(b),c&&c.length>0&&(b+="___"+ma(c)),b.length>28&&(b=b.substr(0,28)+(b.length-28)),c=b,b=H(ka,"_p",I()),H(b,c,I())[a]=(new Date).getTime(),R(a,"_p",c))},ma=function(a){return a.join("__").replace(/\./g,"_").replace(/\-/g,"_").replace(/,/g,"_")};var na=I(),U=[],V=function(a){throw Error("Bad hint: "+a);};U.push(["jsl",function(a){for(var b in a)if(Object.prototype.hasOwnProperty.call(a,b)){var c=a[b];typeof c=="object"?M[b]=H(M,b,[]).concat(c):H(M,b,c)}if(b=a.u)a=H(M,"us",[]),a.push(b),(b=/^https:(.*)$/.exec(b))&&a.push("http:"+b[1])}]);var oa=/^(\/[a-zA-Z0-9_\-]+)+$/,pa=[/\/amp\//,/\/amp$/,/^\/amp$/],qa=/^[a-zA-Z0-9\-_\.,!]+$/,ra=/^gapi\.loaded_[0-9]+$/,sa=/^[a-zA-Z0-9,._-]+$/,wa=function(a,b,c,d,e){var f=a.split(";"),k=f.shift(),l=na[k],p=null;l?p=l(f,b,c,d):V("no hint processor for: "+k);p||V("failed to generate load url");b=p;c=b.match(ta);(d=b.match(ua))&&d.length===1&&va.test(b)&&c&&c.length===1||V("failed sanity: "+a);try{a="?";if(e&&e.length>0){c=b=0;for(d={};c";F.write(Y?Y.createHTML(a):a)}},Da=function(a){var b=F.createElement(X);b.setAttribute("src",Y?Y.createScriptURL(a):a);a=Ca();a!==null&&b.setAttribute("nonce",a);b.async="true";(a=F.getElementsByTagName(X)[0])?a.parentNode.insertBefore(b,a):(F.head||F.body||F.documentElement).appendChild(b)},Ga=function(a,b,c){Fa(function(){var d=b===N()?H(J,"_",I()):I();d=H(O(b),"_",d);a(d)},c)},Ia=function(a,b){var c= +b||{};typeof b=="function"&&(c={},c.callback=b);var d=(b=c)&&b._c;if(d)for(var e=0;e0&&(q=E.setTimeout(function(){z=!0;k()},f));var r=Ba(a,G);if(r.length){r=Ba(a,l);var u=H(M,"CP",[]),v=u.length;u[v]=function(w){if(!w)return 0;T("ml1",r,K);var B=function(L){u[v]=null;la(r,w)&&ja(function(){d&&d();L()})},C= +function(){var L=u[v+1];L&&L()};v>0&&u[v-1]?u[v]=function(){B(C)}:B(C)};if(r.length){var S="loaded_"+M.I++;J[S]=function(w){u[v](w);J[S]=null};a=wa(c,r,"gapi."+S,l,Ma);l.push.apply(l,r);T("ml0",r,K);b.sync||E.___gapisync?Ea(a):Da(a)}else u[v](fa)}else la(r)&&d&&d()},Ja;var Ka=null,Z=m.trustedTypes;if(Z&&Z.createPolicy)try{Ka=Z.createPolicy("gapi#gapi",{createHTML:t,createScript:t,createScriptURL:t})}catch(a){m.console&&m.console.error(a.message)}Ja=Ka;var Y=Ja;var Fa=function(a,b){if(M.hee&&M.hel>0)try{return a()}catch(c){b&&b(c),M.hel--,Ia("debug_error",function(){try{window.___jsl.hefn(c)}catch(d){throw c;}})}else try{return a()}catch(c){throw b&&b(c),c;}};var La=J.load;La&&H(M,"ol",[]).push(La);J.load=function(a,b){return Fa(function(){return Ia(a,b)})};U.unshift(["url",function(a,b,c){!a||b&&b!==""||!a.endsWith(".js")||(a=a.substring(0,a.length-3),b=a.lastIndexOf("/")+1,b>=a.length||(a=a.substr(b).split(":").filter(function(d){return!["api","platform"].includes(d)}),c.features=a))}]);Q.bs0=window.gapi._bs||(new Date).getTime();R("bs0");Q.bs1=(new Date).getTime();R("bs1");delete window.gapi._bs;window.gapi.load("",{callback:window["gapi_onload"],_c:{url:"https://apis.google.com/js/api.js",jsl:{ci:{"oauth-flow":{authUrl:"https://accounts.google.com/o/oauth2/auth",proxyUrl:"https://accounts.google.com/o/oauth2/postmessageRelay",disableOpt:!0,idpIframeUrl:"https://accounts.google.com/o/oauth2/iframe",usegapi:!1},debug:{reportExceptionRate:1,forceIm:!1,rethrowException:!0,host:"https://apis.google.com"},gen204logger:{ interval: 30000, rate: 0.01, batch: false },enableMultilogin:!0,"googleapis.config":{auth:{useFirstPartyAuthV2:!0},root:"https://content.googleapis.com","root-1p":"https://clients6.google.com"}, +inline:{css:1},disableRealtimeCallback:!1,drive_share:{skipInitCommand:!0},csi:{rate:.01},client:{cors:!1},signInDeprecation:{rate:0},include_granted_scopes:!0,llang:"en",iframes:{youtube:{params:{location:["search","hash"]},url:":socialhost:/:session_prefix:_/widget/render/youtube?usegapi=1",methods:["scroll","openwindow"]},ytsubscribe:{url:"https://www.youtube.com/subscribe_embed?usegapi=1"},plus_circle:{params:{url:""},url:":socialhost:/:session_prefix::se:_/widget/plus/circle?usegapi=1"}, +plus_share:{params:{url:""},url:":socialhost:/:session_prefix::se:_/+1/sharebutton?plusShare=true&usegapi=1"},rbr_s:{params:{url:""},url:":socialhost:/:session_prefix::se:_/widget/render/recobarsimplescroller"},":source:":"3p",playemm:{url:"https://play.google.com/work/embedded/search?usegapi=1&usegapi=1"},savetoandroidpay:{url:"https://pay.google.com/gp/v/widget/save"},blogger:{params:{location:["search","hash"]},url:":socialhost:/:session_prefix:_/widget/render/blogger?usegapi=1",methods:["scroll", +"openwindow"]},evwidget:{params:{url:""},url:":socialhost:/:session_prefix:_/events/widget?usegapi=1"},partnersbadge:{url:"https://www.gstatic.com/partners/badge/templates/badge.html?usegapi=1"},dataconnector:{url:"https://dataconnector.corp.google.com/:session_prefix:ui/widgetview?usegapi=1"},surveyoptin:{url:"https://www.google.com/shopping/customerreviews/optin?usegapi=1"},":socialhost:":"https://apis.google.com",shortlists:{url:""},hangout:{url:"https://talkgadget.google.com/:session_prefix:talkgadget/_/widget"}, +plus_followers:{params:{url:""},url:":socialhost:/_/im/_/widget/render/plus/followers?usegapi=1"},post:{params:{url:""},url:":socialhost:/:session_prefix::im_prefix:_/widget/render/post?usegapi=1"},signin:{params:{url:""},url:":socialhost:/:session_prefix:_/widget/render/signin?usegapi=1",methods:["onauth"]},rbr_i:{params:{url:""},url:":socialhost:/:session_prefix::se:_/widget/render/recobarinvitation"},share:{url:":socialhost:/:session_prefix::im_prefix:_/widget/render/share?usegapi=1"},plusone:{params:{count:"", +size:"",url:""},url:":socialhost:/:session_prefix::se:_/+1/fastbutton?usegapi=1"},comments:{params:{location:["search","hash"]},url:":socialhost:/:session_prefix:_/widget/render/comments?usegapi=1",methods:["scroll","openwindow"]},":im_socialhost:":"https://plus.googleapis.com",backdrop:{url:"https://clients3.google.com/cast/chromecast/home/widget/backdrop?usegapi=1"},visibility:{params:{url:""},url:":socialhost:/:session_prefix:_/widget/render/visibility?usegapi=1"},autocomplete:{params:{url:""},url:":socialhost:/:session_prefix:_/widget/render/autocomplete"}, +":signuphost:":"https://plus.google.com",ratingbadge:{url:"https://www.google.com/shopping/merchantverse/?usegapi=1"},appcirclepicker:{url:":socialhost:/:session_prefix:_/widget/render/appcirclepicker"},follow:{url:":socialhost:/:session_prefix:_/widget/render/follow?usegapi=1"},community:{url:":ctx_socialhost:/:session_prefix::im_prefix:_/widget/render/community?usegapi=1"},sharetoclassroom:{url:"https://classroom.google.com/sharewidget?usegapi=1"},"sharetoclassroom-boq":{url:"https://classroom.google.com/sharewidget-boq?usegapi=1"},ytshare:{params:{url:""}, +url:":socialhost:/:session_prefix:_/widget/render/ytshare?usegapi=1"},plus:{url:":socialhost:/:session_prefix:_/widget/render/badge?usegapi=1"},family_creation:{params:{url:""},url:"https://families.google.com/webcreation?usegapi=1&usegapi=1"},commentcount:{url:":socialhost:/:session_prefix:_/widget/render/commentcount?usegapi=1"},configurator:{url:":socialhost:/:session_prefix:_/plusbuttonconfigurator?usegapi=1"},zoomableimage:{url:"https://ssl.gstatic.com/microscope/embed/"},appfinder:{url:"https://workspace.google.com/:session_prefix:marketplace/appfinder?usegapi=1"}, +savetowallet:{url:"https://pay.google.com/gp/v/widget/save"},person:{url:":socialhost:/:session_prefix:_/widget/render/person?usegapi=1"},savetodrive:{url:"https://drive.google.com/savetodrivebutton?usegapi=1",methods:["save"]},page:{url:":socialhost:/:session_prefix:_/widget/render/page?usegapi=1"},card:{url:":socialhost:/:session_prefix:_/hovercard/card"}}},h:"m;/_/scs/abc-static/_/js/k=gapi.lb.en.PCvl17LujMs.O/d=1/rs=AHpOoo-sAn5Asuf3MvShXCH_dsg8tE46Tw/m=__features__",u:"https://apis.google.com/js/api.js",hee:!0,dpo:!1,le:["scs"]},platform:"backdrop blogger comments commentcount community donation family_creation follow hangout health page partnersbadge person playemm playreview plus plusone post ratingbadge savetoandroidpay savetodrive savetowallet sharetoclassroom shortlists signin2 surveyoptin visibility youtube ytsubscribe zoomableimage".split(" "), +annotation:["interactivepost","recobar","signin2","autocomplete"]}});H(M,"le",[]).push("fedcm_migration_mod");}).call(this); diff --git a/จัดการตำแหน่ง Node n8n_files/cb=gapi(1).loaded_0 b/จัดการตำแหน่ง Node n8n_files/cb=gapi(1).loaded_0 new file mode 100644 index 0000000..29dd36b --- /dev/null +++ b/จัดการตำแหน่ง Node n8n_files/cb=gapi(1).loaded_0 @@ -0,0 +1,731 @@ +gapi.loaded_0(function(_){var window=this; +_._F_toggles_initialize=function(a){(typeof globalThis!=="undefined"?globalThis:typeof self!=="undefined"?self:this)._F_toggles=a||[]};(0,_._F_toggles_initialize)([]); +var fa,ia,la,oa,Ca,Da,Fa,Ia;_.da=function(a){return function(){return _.ca[a].apply(this,arguments)}};_.ca=[];fa=typeof Object.create=="function"?Object.create:function(a){var b=function(){};b.prototype=a;return new b};ia=typeof Object.defineProperties=="function"?Object.defineProperty:function(a,b,c){if(a==Array.prototype||a==Object.prototype)return a;a[b]=c.value;return a}; +la=function(a){a=["object"==typeof globalThis&&globalThis,a,"object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global];for(var b=0;b0;){var a=this.yC.pop();if(a in this.iw)return a}return null};Sa.prototype.getNext=Sa.prototype.wea;sa("globalThis",function(a){return a||_.na});sa("Reflect.setPrototypeOf",function(a){return a?a:Ca?function(b,c){try{return Ca(b,c),!0}catch(d){return!1}}:null}); +sa("Symbol",function(a){if(a)return a;var b=function(f,h){this.q4=f;ia(this,"description",{configurable:!0,writable:!0,value:h})};b.prototype.toString=function(){return this.q4};var c="jscomp_symbol_"+(Math.random()*1E9>>>0)+"_",d=0,e=function(f){if(this instanceof e)throw new TypeError("Symbol is not a constructor");return new b(c+(f||"")+"_"+d++,f)};return e}); +sa("Symbol.iterator",function(a){if(a)return a;a=Symbol("Symbol.iterator");ia(Array.prototype,a,{configurable:!0,writable:!0,value:function(){return Va(Da(this))}});return a});var Va=function(a){a={next:a};a[Symbol.iterator]=function(){return this};return a}; +sa("Promise",function(a){function b(){this.xf=null}function c(h){return h instanceof e?h:new e(function(k){k(h)})}if(a)return a;b.prototype.cQ=function(h){if(this.xf==null){this.xf=[];var k=this;this.dQ(function(){k.Uca()})}this.xf.push(h)};var d=_.na.setTimeout;b.prototype.dQ=function(h){d(h,0)};b.prototype.Uca=function(){for(;this.xf&&this.xf.length;){var h=this.xf;this.xf=[];for(var k=0;k=f}});sa("Object.setPrototypeOf",function(a){return a||Ca});sa("Symbol.dispose",function(a){return a?a:Symbol("Symbol.dispose")}); +sa("WeakMap",function(a){function b(){}function c(l){var m=typeof l;return m==="object"&&l!==null||m==="function"}function d(l){if(!Fa(l,f)){var m=new b;ia(l,f,{value:m})}}function e(l){var m=Object[l];m&&(Object[l]=function(n){if(n instanceof b)return n;Object.isExtensible(n)&&d(n);return m(n)})}if(function(){if(!a||!Object.seal)return!1;try{var l=Object.seal({}),m=Object.seal({}),n=new a([[l,2],[m,3]]);if(n.get(l)!=2||n.get(m)!=3)return!1;n.delete(l);n.set(m,4);return!n.has(l)&&n.get(m)==4}catch(p){return!1}}())return a; +var f="$jscomp_hidden_"+Math.random();e("freeze");e("preventExtensions");e("seal");var h=0,k=function(l){this.Fa=(h+=Math.random()+1).toString();if(l){l=_.Ea(l);for(var m;!(m=l.next()).done;)m=m.value,this.set(m[0],m[1])}};k.prototype.set=function(l,m){if(!c(l))throw Error("e");d(l);if(!Fa(l,f))throw Error("f`"+l);l[f][this.Fa]=m;return this};k.prototype.get=function(l){return c(l)&&Fa(l,f)?l[f][this.Fa]:void 0};k.prototype.has=function(l){return c(l)&&Fa(l,f)&&Fa(l[f],this.Fa)};k.prototype.delete= +function(l){return c(l)&&Fa(l,f)&&Fa(l[f],this.Fa)?delete l[f][this.Fa]:!1};return k}); +sa("Map",function(a){if(function(){if(!a||typeof a!="function"||!a.prototype.entries||typeof Object.seal!="function")return!1;try{var k=Object.seal({x:4}),l=new a(_.Ea([[k,"s"]]));if(l.get(k)!="s"||l.size!=1||l.get({x:4})||l.set({x:4},"t")!=l||l.size!=2)return!1;var m=l.entries(),n=m.next();if(n.done||n.value[0]!=k||n.value[1]!="s")return!1;n=m.next();return n.done||n.value[0].x!=4||n.value[1]!="t"||!m.next().done?!1:!0}catch(p){return!1}}())return a;var b=new WeakMap,c=function(k){this[0]={};this[1]= +f();this.size=0;if(k){k=_.Ea(k);for(var l;!(l=k.next()).done;)l=l.value,this.set(l[0],l[1])}};c.prototype.set=function(k,l){k=k===0?0:k;var m=d(this,k);m.list||(m.list=this[0][m.id]=[]);m.entry?m.entry.value=l:(m.entry={next:this[1],Nk:this[1].Nk,head:this[1],key:k,value:l},m.list.push(m.entry),this[1].Nk.next=m.entry,this[1].Nk=m.entry,this.size++);return this};c.prototype.delete=function(k){k=d(this,k);return k.entry&&k.list?(k.list.splice(k.index,1),k.list.length||delete this[0][k.id],k.entry.Nk.next= +k.entry.next,k.entry.next.Nk=k.entry.Nk,k.entry.head=null,this.size--,!0):!1};c.prototype.clear=function(){this[0]={};this[1]=this[1].Nk=f();this.size=0};c.prototype.has=function(k){return!!d(this,k).entry};c.prototype.get=function(k){return(k=d(this,k).entry)&&k.value};c.prototype.entries=function(){return e(this,function(k){return[k.key,k.value]})};c.prototype.keys=function(){return e(this,function(k){return k.key})};c.prototype.values=function(){return e(this,function(k){return k.value})};c.prototype.forEach= +function(k,l){for(var m=this.entries(),n;!(n=m.next()).done;)n=n.value,k.call(l,n[1],n[0],this)};c.prototype[Symbol.iterator]=c.prototype.entries;var d=function(k,l){var m=l&&typeof l;m=="object"||m=="function"?b.has(l)?m=b.get(l):(m=""+ ++h,b.set(l,m)):m="p_"+l;var n=k[0][m];if(n&&Fa(k[0],m))for(k=0;k=0&&b56319||b+1===d)return e;b=c.charCodeAt(b+1);return b<56320||b>57343?e:(e-55296)*1024+b+9216}}}); +sa("String.fromCodePoint",function(a){return a?a:function(b){for(var c="",d=0;d1114111||e!==Math.floor(e))throw new RangeError("invalid_code_point "+e);e<=65535?c+=String.fromCharCode(e):(e-=65536,c+=String.fromCharCode(e>>>10&1023|55296),c+=String.fromCharCode(e&1023|56320))}return c}});sa("Object.entries",function(a){return a?a:function(b){var c=[],d;for(d in b)Fa(b,d)&&c.push([d,b[d]]);return c}}); +sa("String.prototype.endsWith",function(a){return a?a:function(b,c){var d=Ya(this,b,"endsWith");c===void 0&&(c=d.length);c=Math.max(0,Math.min(c|0,d.length));for(var e=b.length;e>0&&c>0;)if(d[--c]!=b[--e])return!1;return e<=0}});sa("Number.isFinite",function(a){return a?a:function(b){return typeof b!=="number"?!1:!isNaN(b)&&b!==Infinity&&b!==-Infinity}}); +sa("Array.prototype.find",function(a){return a?a:function(b,c){a:{var d=this;d instanceof String&&(d=String(d));for(var e=d.length,f=0;f0?(d=Array.prototype.flat.call(d,b-1),c.push.apply(c,d)):c.push(d)});return c}});sa("Number.MAX_SAFE_INTEGER",function(){return 9007199254740991});sa("Number.MIN_SAFE_INTEGER",function(){return-9007199254740991}); +sa("Number.isInteger",function(a){return a?a:function(b){return Number.isFinite(b)?b===Math.floor(b):!1}});sa("Number.isSafeInteger",function(a){return a?a:function(b){return Number.isInteger(b)&&Math.abs(b)<=Number.MAX_SAFE_INTEGER}});sa("Array.prototype.flatMap",function(a){return a?a:function(b,c){var d=[];Array.prototype.forEach.call(this,function(e,f){e=b.call(c,e,f,this);Array.isArray(e)?d.push.apply(d,e):d.push(e)});return d}}); +sa("Math.trunc",function(a){return a?a:function(b){b=Number(b);if(isNaN(b)||b===Infinity||b===-Infinity||b===0)return b;var c=Math.floor(Math.abs(b));return b<0?-c:c}});sa("Number.isNaN",function(a){return a?a:function(b){return typeof b==="number"&&isNaN(b)}}); +sa("String.prototype.replaceAll",function(a){return a?a:function(b,c){if(b instanceof RegExp&&!b.global)throw new TypeError("String.prototype.replaceAll called with a non-global RegExp argument.");return b instanceof RegExp?this.replace(b,c):this.replace(new RegExp(String(b).replace(/([-()\[\]{}+?*.$\^|,:#=this.length))return this[a]};sa("Array.prototype.at",function(a){return a?a:ab});ra("at",function(a){return a?a:ab});sa("String.prototype.at",function(a){return a?a:ab});sa("Math.imul",function(a){return a?a:function(b,c){b=Number(b);c=Number(c);var d=b&65535,e=c&65535;return d*e+((b>>>16&65535)*e+d*(c>>>16&65535)<<16>>>0)|0}});_.bb={};/* + + Copyright The Closure Library Authors. + SPDX-License-Identifier: Apache-2.0 +*/ +_.db=_.db||{};_.fb=this||self;_.gb=_.fb._F_toggles||[];_.ib="closure_uid_"+(Math.random()*1E9>>>0);_.kb=function(a,b){var c=Array.prototype.slice.call(arguments,1);return function(){var d=c.slice();d.push.apply(d,arguments);return a.apply(this,d)}};_.x=function(a,b){a=a.split(".");for(var c=_.fb,d;a.length&&(d=a.shift());)a.length||b===void 0?c=c[d]&&c[d]!==Object.prototype[d]?c[d]:c[d]={}:c[d]=b};_.mb=window.osapi=window.osapi||{}; +window.___jsl=window.___jsl||{}; +(window.___jsl.cd=window.___jsl.cd||[]).push({gwidget:{parsetags:"explicit"},appsapi:{plus_one_service:"/plus/v1"},csi:{rate:.01},poshare:{hangoutContactPickerServer:"https://plus.google.com"},gappsutil:{required_scopes:["https://www.googleapis.com/auth/plus.me","https://www.googleapis.com/auth/plus.people.recommended"],display_on_page_ready:!1},appsutil:{required_scopes:["https://www.googleapis.com/auth/plus.me","https://www.googleapis.com/auth/plus.people.recommended"],display_on_page_ready:!1}, +"oauth-flow":{authUrl:"https://accounts.google.com/o/oauth2/auth",proxyUrl:"https://accounts.google.com/o/oauth2/postmessageRelay",redirectUri:"postmessage"},iframes:{sharebox:{params:{json:"&"},url:":socialhost:/:session_prefix:_/sharebox/dialog"},plus:{url:":socialhost:/:session_prefix:_/widget/render/badge?usegapi=1"},":socialhost:":"https://apis.google.com",":im_socialhost:":"https://plus.googleapis.com",domains_suggest:{url:"https://domains.google.com/suggest/flow"},card:{params:{s:"#",userid:"&"}, +url:":socialhost:/:session_prefix:_/hovercard/internalcard"},":signuphost:":"https://plus.google.com",":gplus_url:":"https://plus.google.com",plusone:{url:":socialhost:/:session_prefix:_/+1/fastbutton?usegapi=1"},plus_share:{url:":socialhost:/:session_prefix:_/+1/sharebutton?plusShare=true&usegapi=1"},plus_circle:{url:":socialhost:/:session_prefix:_/widget/plus/circle?usegapi=1"},plus_followers:{url:":socialhost:/_/im/_/widget/render/plus/followers?usegapi=1"},configurator:{url:":socialhost:/:session_prefix:_/plusbuttonconfigurator?usegapi=1"}, +appcirclepicker:{url:":socialhost:/:session_prefix:_/widget/render/appcirclepicker"},page:{url:":socialhost:/:session_prefix:_/widget/render/page?usegapi=1"},person:{url:":socialhost:/:session_prefix:_/widget/render/person?usegapi=1"},community:{url:":ctx_socialhost:/:session_prefix::im_prefix:_/widget/render/community?usegapi=1"},follow:{url:":socialhost:/:session_prefix:_/widget/render/follow?usegapi=1"},commentcount:{url:":socialhost:/:session_prefix:_/widget/render/commentcount?usegapi=1"},comments:{url:":socialhost:/:session_prefix:_/widget/render/comments?usegapi=1"}, +blogger:{url:":socialhost:/:session_prefix:_/widget/render/blogger?usegapi=1"},youtube:{url:":socialhost:/:session_prefix:_/widget/render/youtube?usegapi=1"},reportabuse:{url:":socialhost:/:session_prefix:_/widget/render/reportabuse?usegapi=1"},additnow:{url:":socialhost:/additnow/additnow.html"},appfinder:{url:"https://workspace.google.com/:session_prefix:marketplace/appfinder?usegapi=1"},":source:":"1p"},poclient:{update_session:"google.updateSessionCallback"},"googleapis.config":{rpc:"/rpc",root:"https://content.googleapis.com", +"root-1p":"https://clients6.google.com",useGapiForXd3:!0,xd3:"/static/proxy.html",auth:{useInterimAuth:!1}},report:{apis:["iframes\\..*","gadgets\\..*","gapi\\.appcirclepicker\\..*","gapi\\.client\\..*"],rate:1E-4},client:{perApiBatch:!0},gen204logger:{interval:3E4,rate:.001,batch:!1}}); +var pb;_.nb=function(a,b){if(Error.captureStackTrace)Error.captureStackTrace(this,_.nb);else{var c=Error().stack;c&&(this.stack=c)}a&&(this.message=String(a));b!==void 0&&(this.cause=b);this.O_=!0};pb=function(a,b){a=a.split("%s");for(var c="",d=a.length-1,e=0;e=0};_.wb=function(a){var b=[],c=0,d;for(d in a)b[c++]=a[d];return b};_.xb=function(a){var b=typeof a;return b=="object"&&a!=null||b=="function"};_.yb=function(a,b){a=a.split(".");b=b||_.fb;for(var c=0;c2){var d=Array.prototype.slice.call(arguments,2);return function(){var e=Array.prototype.slice.call(arguments);Array.prototype.unshift.apply(e,d);return a.apply(b,e)}}return function(){return a.apply(b,arguments)}}; +_.Db=function(a,b,c){_.Db=Function.prototype.bind&&Function.prototype.bind.toString().indexOf("native code")!=-1?Ab:Cb;return _.Db.apply(null,arguments)};_.tb=Array.prototype.indexOf?function(a,b){return Array.prototype.indexOf.call(a,b,void 0)}:function(a,b){if(typeof a==="string")return typeof b!=="string"||b.length!=1?-1:a.indexOf(b,0);for(var c=0;c=0;c--)if(c in a&&a[c]===b)return c;return-1};_.Hb=Array.prototype.forEach?function(a,b,c){Array.prototype.forEach.call(a,b,c)}:function(a,b,c){for(var d=a.length,e=typeof a==="string"?a.split(""):a,f=0;f>18&1),Pb=!!(_.gb[0]&8192),Qb=!!(_.gb[0]>>20&1),Rb=!!(_.gb[0]&32),Sb=!!(_.gb[0]>>21&1),Tb=!!(_.gb[0]&512),Wb=!!(_.gb[0]&2048);var Xb;Xb=zb(1,!0);_.Yb=Ob?Qb:zb(610401301,!1);_.Zb=Ob?Rb:zb(1331761403,!1);_.$b=Ob?Sb:zb(651175828,!1);_.ac=Ob?Pb||!Tb:zb(748402147,!0);_.bc=Ob?Pb||!Wb:zb(824656860,Xb);_.cc=function(a){_.cc[" "](a);return a};_.cc[" "]=function(){}; +/* + + Copyright Google LLC + SPDX-License-Identifier: Apache-2.0 +*/ +var hc,jc,zc,Mc,Uc,gd,rd;_.dc=function(a){var b=a.length;if(b>0){for(var c=Array(b),d=0;d/g,">").replace(/"/g,""").replace(/'/g,"'");if(b==null?0:b.yxa)a=a.replace(/(^|[\r\n\t ]) /g,"$1 ");if(b==null?0:b.pja)a=a.replace(/(\r\n|\n|\r)/g,"
");if(b==null?0:b.zxa)a=a.replace(/(\t+)/g,'$1');return _.lc(a)}; +_.Gc=function(a){var b=_.Fc.apply(1,arguments);if(b.length===0)return _.qc(a[0]);for(var c=a[0],d=0;db?1:0};_.Oc=function(a,b){b=_.Dc(b);b!==void 0&&(a.href=b)};_.Pc=function(a,b,c,d){b=_.Dc(b);return b!==void 0?a.open(b,c,d):null};_.Qc=function(a,b){b=b===void 0?document:b;var c,d;b=(d=(c=b).querySelector)==null?void 0:d.call(c,a+"[nonce]");return b==null?"":b.nonce||b.getAttribute("nonce")||""};_.Rc=function(a,b){if(a.nodeType===1&&/^(script|style)$/i.test(a.tagName))throw Error("j");a.innerHTML=_.mc(b)}; +_.Sc=function(){var a=_.fb.navigator;return a&&(a=a.userAgent)?a:""};Uc=function(a){if(!_.Yb||!_.Tc)return!1;for(var b=0;b<_.Tc.brands.length;b++){var c=_.Tc.brands[b].brand;if(c&&_.Kc(c,a))return!0}return!1};_.Vc=function(a){return _.Kc(_.Sc(),a)};_.Wc=function(a){for(var b=RegExp("([A-Z][\\w ]+)/([^\\s]+)\\s*(?:\\((.*?)\\))?","g"),c=[],d;d=b.exec(a);)c.push([d[1],d[2],d[3]||void 0]);return c};_.Xc=function(){return _.Yb?!!_.Tc&&_.Tc.brands.length>0:!1};_.Yc=function(){return _.Xc()?!1:_.Vc("Opera")}; +_.Zc=function(){return _.Xc()?!1:_.Vc("Trident")||_.Vc("MSIE")};_.$c=function(){return _.Xc()?!1:_.Vc("Edge")};_.ad=function(){return _.Xc()?Uc("Microsoft Edge"):_.Vc("Edg/")};_.bd=function(){return _.Xc()?Uc("Opera"):_.Vc("OPR")};_.cd=function(){return _.Vc("Firefox")||_.Vc("FxiOS")};_.dd=function(){return _.Xc()?Uc("Chromium"):(_.Vc("Chrome")||_.Vc("CriOS"))&&!_.$c()||_.Vc("Silk")}; +_.ed=function(a){var b={};a.forEach(function(c){b[c[0]]=c[1]});return function(c){return b[c.find(function(d){return d in b})]||""}};_.fd=function(a){var b=/rv: *([\d\.]*)/.exec(a);if(b&&b[1])return b[1];b="";var c=/MSIE +([\d\.]+)/.exec(a);if(c&&c[1])if(a=/Trident\/(\d.\d)/.exec(a),c[1]=="7.0")if(a&&a[1])switch(a[1]){case "4.0":b="8.0";break;case "5.0":b="9.0";break;case "6.0":b="10.0";break;case "7.0":b="11.0"}else b="7.0";else b=c[1];return b}; +gd=function(){return _.Yb?!!_.Tc&&!!_.Tc.platform:!1};_.id=function(){return gd()?_.Tc.platform==="Android":_.Vc("Android")};_.jd=function(){return _.Vc("iPhone")&&!_.Vc("iPod")&&!_.Vc("iPad")};_.kd=function(){return _.jd()||_.Vc("iPad")||_.Vc("iPod")};_.ld=function(){return gd()?_.Tc.platform==="macOS":_.Vc("Macintosh")};_.md=function(){return gd()?_.Tc.platform==="Windows":_.Vc("Windows")};_.nd=function(){return gd()?_.Tc.platform==="Chrome OS":_.Vc("CrOS")}; +_.Na.prototype.Qs=_.rb(0,function(){if(this.YI)throw new TypeError("Generator is already running");this.YI=!0});_.pd=function(a,b){a.raw=b;Object.freeze&&(Object.freeze(a),Object.freeze(b));return a};_.qd=function(a){return _.pd(a,a)};_.Fc=function(){for(var a=Number(this),b=[],c=a;cparseFloat(Xd)){Wd=String(Zd);break a}}Wd=Xd}_.$d=Wd;if(_.fb.document&&_.Fd){var be=Vd();ae=be?be:parseInt(_.$d,10)||void 0}else ae=void 0;_.ce=ae;var ie,pe,oe;_.fe=function(a){return a?new _.de(_.ee(a)):rd||(rd=new _.de)};_.ge=function(a,b){return typeof b==="string"?a.getElementById(b):b};_.he=function(a,b,c,d){a=d||a;return(b=b&&b!="*"?String(b).toUpperCase():"")||c?a.querySelectorAll(b+(c?"."+c:"")):a.getElementsByTagName("*")}; +_.je=function(a,b){_.ec(b,function(c,d){d=="style"?a.style.cssText=c:d=="class"?a.className=c:d=="for"?a.htmlFor=c:ie.hasOwnProperty(d)?a.setAttribute(ie[d],c):_.Ic(d,"aria-")||_.Ic(d,"data-")?a.setAttribute(d,c):a[d]=c})};ie={cellpadding:"cellPadding",cellspacing:"cellSpacing",colspan:"colSpan",frameborder:"frameBorder",height:"height",maxlength:"maxLength",nonce:"nonce",role:"role",rowspan:"rowSpan",type:"type",usemap:"useMap",valign:"vAlign",width:"width"};_.le=function(a){return _.ke(a||window)}; +_.ke=function(a){a=a.document;a=_.me(a)?a.documentElement:a.body;return new _.Hc(a.clientWidth,a.clientHeight)};_.ne=function(a){return a?a.defaultView:window};_.qe=function(a,b){var c=b[1],d=oe(a,String(b[0]));c&&(typeof c==="string"?d.className=c:Array.isArray(c)?d.className=c.join(" "):_.je(d,c));b.length>2&&pe(a,d,b,2);return d}; +pe=function(a,b,c,d){function e(k){k&&b.appendChild(typeof k==="string"?a.createTextNode(k):k)}for(;d0)e(f);else{a:{if(f&&typeof f.length=="number"){if(_.xb(f)){var h=typeof f.item=="function"||typeof f.item=="string";break a}if(typeof f==="function"){h=typeof f.item=="function";break a}}h=!1}_.Hb(h?_.dc(f):f,e)}}};_.re=function(a){return oe(document,a)}; +oe=function(a,b){b=String(b);a.contentType==="application/xhtml+xml"&&(b=b.toLowerCase());return a.createElement(b)};_.me=function(a){return a.compatMode=="CSS1Compat"};_.se=function(a){if(a.nodeType!=1)return!1;switch(a.tagName){case "APPLET":case "AREA":case "BASE":case "BR":case "COL":case "COMMAND":case "EMBED":case "FRAME":case "HR":case "IMG":case "INPUT":case "IFRAME":case "ISINDEX":case "KEYGEN":case "LINK":case "NOFRAMES":case "NOSCRIPT":case "META":case "OBJECT":case "PARAM":case "SCRIPT":case "SOURCE":case "STYLE":case "TRACK":case "WBR":return!1}return!0}; +_.te=function(a,b){pe(_.ee(a),a,arguments,1)};_.ue=function(a){for(var b;b=a.firstChild;)a.removeChild(b)};_.ve=function(a,b){b.parentNode&&b.parentNode.insertBefore(a,b)};_.we=function(a){return a&&a.parentNode?a.parentNode.removeChild(a):null};_.xe=function(a){return a.children!=void 0?a.children:Array.prototype.filter.call(a.childNodes,function(b){return b.nodeType==1})};_.ye=function(a){return _.xb(a)&&a.nodeType==1}; +_.ze=function(a,b){if(!a||!b)return!1;if(a.contains&&b.nodeType==1)return a==b||a.contains(b);if(typeof a.compareDocumentPosition!="undefined")return a==b||!!(a.compareDocumentPosition(b)&16);for(;b&&a!=b;)b=b.parentNode;return b==a};_.ee=function(a){return a.nodeType==9?a:a.ownerDocument||a.document}; +_.Ae=function(a,b){if("textContent"in a)a.textContent=b;else if(a.nodeType==3)a.data=String(b);else if(a.firstChild&&a.firstChild.nodeType==3){for(;a.lastChild!=a.firstChild;)a.removeChild(a.lastChild);a.firstChild.data=String(b)}else _.ue(a),a.appendChild(_.ee(a).createTextNode(String(b)))};_.de=function(a){this.zc=a||_.fb.document||document};_.g=_.de.prototype;_.g.Ha=_.fe;_.g.XL=_.da(4);_.g.wb=function(){return this.zc};_.g.U=_.da(5);_.g.getElementsByTagName=function(a,b){return(b||this.zc).getElementsByTagName(String(a))}; +_.g.UH=_.da(6);_.g.Ba=function(a,b,c){return _.qe(this.zc,arguments)};_.g.createElement=function(a){return oe(this.zc,a)};_.g.createTextNode=function(a){return this.zc.createTextNode(String(a))};_.g.getWindow=function(){return this.zc.defaultView};_.g.appendChild=function(a,b){a.appendChild(b)};_.g.append=_.te;_.g.canHaveChildren=_.se;_.g.qe=_.ue;_.g.tW=_.ve;_.g.removeNode=_.we;_.g.eH=_.xe;_.g.isElement=_.ye;_.g.contains=_.ze;_.g.yH=_.ee;_.g.xj=_.da(7); +/* + gapi.loader.OBJECT_CREATE_TEST_OVERRIDE &&*/ +_.Be=function(a){return a===null?"null":a===void 0?"undefined":a};_.De=window;_.Ee=document;_.Fe=_.De.location;_.Ge=/\[native code\]/;_.He=function(a,b,c){return a[b]=a[b]||c};_.Ie=function(){var a;if((a=Object.create)&&_.Ge.test(a))a=a(null);else{a={};for(var b in a)a[b]=void 0}return a};_.Je=function(a,b){return Object.prototype.hasOwnProperty.call(a,b)};_.Ke=function(a,b){a=a||{};for(var c in a)_.Je(a,c)&&(b[c]=a[c])};_.Le=_.He(_.De,"gapi",{});_.Me=function(a,b,c){var d=new RegExp("([#].*&|[#])"+b+"=([^&#]*)","g");b=new RegExp("([?#].*&|[?#])"+b+"=([^&#]*)","g");if(a=a&&(d.exec(a)||b.exec(a)))try{c=decodeURIComponent(a[2])}catch(e){}return c};_.Ne=new RegExp(/^/.source+/([a-zA-Z][-+.a-zA-Z0-9]*:)?/.source+/(\/\/[^\/?#]*)?/.source+/([^?#]*)?/.source+/(\?([^#]*))?/.source+/(#((#|[^#])*))?/.source+/$/.source);_.Oe=new RegExp(/(%([^0-9a-fA-F%]|[0-9a-fA-F]([^0-9a-fA-F%])?)?)*/.source+/%($|[^0-9a-fA-F]|[0-9a-fA-F]($|[^0-9a-fA-F]))/.source,"g"); +_.Pe=new RegExp(/\/?\??#?/.source+"("+/[\/?#]/i.source+"|"+/[\uD800-\uDBFF]/i.source+"|"+/%[c-f][0-9a-f](%[89ab][0-9a-f]){0,2}(%[89ab]?)?/i.source+"|"+/%[0-9a-f]?/i.source+")$","i");_.Re=function(a,b,c){_.Qe(a,b,c,"add","at")};_.Qe=function(a,b,c,d,e){if(a[d+"EventListener"])a[d+"EventListener"](b,c,!1);else if(a[e+"tachEvent"])a[e+"tachEvent"]("on"+b,c)};_.Se={};_.Se=_.He(_.De,"___jsl",_.Ie());_.He(_.Se,"I",0);_.He(_.Se,"hel",10);var Te,Ue,Ve,We,$e,Xe,Ze,af,bf;Te=function(a){var b=window.___jsl=window.___jsl||{};b[a]=b[a]||[];return b[a]};Ue=function(a){var b=window.___jsl=window.___jsl||{};b.cfg=!a&&b.cfg||{};return b.cfg};Ve=function(a){return typeof a==="object"&&/\[native code\]/.test(a.push)}; +We=function(a,b,c){if(b&&typeof b==="object")for(var d in b)!Object.prototype.hasOwnProperty.call(b,d)||c&&d==="___goc"&&typeof b[d]==="undefined"||(a[d]&&b[d]&&typeof a[d]==="object"&&typeof b[d]==="object"&&!Ve(a[d])&&!Ve(b[d])?We(a[d],b[d]):b[d]&&typeof b[d]==="object"?(a[d]=Ve(b[d])?[]:{},We(a[d],b[d])):a[d]=b[d])}; +$e=function(a,b){if(a&&!/^\s+$/.test(a)){for(;a.charCodeAt(a.length-1)==0;)a=a.substring(0,a.length-1);var c=a,d=Te("dm");d.push(20);try{var e=window.JSON.parse(a)}catch(h){}if(typeof e==="object")return d.push(21),e;try{e=window.JSON.parse("{"+a+"}")}catch(h){}if(typeof e==="object")return d.push(22),e;a=a.replace(RegExp("([^\"',{}\\s]+?)\\s*:\\s*(.*?)[,}\\s]","g"),function(h,k,l){l=l.startsWith('"')?"%DOUBLE_QUOTE%"+l.substring(1):l;l=l.endsWith('"')?l.slice(0,-1)+"%DOUBLE_QUOTE%":l;return"%DOUBLE_QUOTE%"+ +k+"%DOUBLE_QUOTE%:"+l});a=a.replace(/\\'/g,"%SINGLE_QUOTE%");a=a.replace(/"/g,'\\"');a=a.replace(/'/g,'"');a=a.replace(/%SINGLE_QUOTE%/g,"'");a=a.replace(/%DOUBLE_QUOTE%/g,'"');try{e=window.JSON.parse(a)}catch(h){}if(typeof e==="object")return d.push(23),e;try{e=window.JSON.parse("{"+a+"}")}catch(h){}if(typeof e==="object")return d.push(24),e;a=document.getElementsByTagName("script")||[];var f;a.length>0&&(f=a[0].nonce||a[0].getAttribute("nonce"));if(f&&f===b||!f&&Xe())if(e=Ze(c),d.push(25),typeof e=== +"object")return e;return{}}};Xe=function(){var a=window.location.hostname;return a?/(^|\.)(2mdn|ampproject|android|appspot|blogger|blogspot|chrome|chromium|doubleclick|gcpnode|ggpht|gmail|google|google-analytics|googleadservices|googleapis|googleapis-cn|googleoptimize|googlers|googlesource|googlesyndication|googletagmanager|googletagservices|googleusercontent|googlevideo|gstatic|tiltbrush|waze|withgoogle|youtube|ytimg)(\.com?|\.net|\.org)?(\.[a-z][a-z]|\.cat)?$/.test(a):!1}; +Ze=function(a){try{var b=(new Function("return ("+a+"\n)"))()}catch(c){}if(typeof b==="object")return b;try{b=(new Function("return ({"+a+"\n})"))()}catch(c){}return b};af=function(a,b){var c={___goc:void 0};a.length&&a[a.length-1]&&Object.hasOwnProperty.call(a[a.length-1],"___goc")&&typeof a[a.length-1].___goc==="undefined"&&(c=a.pop());We(c,b);a.push(c)}; +bf=function(a){Ue(!0);var b=window.___gcfg,c=Te("cu"),d=window.___gu;b&&b!==d&&(af(c,b),window.___gu=b);b=Te("cu");var e=document.getElementsByTagName("script")||[];d=[];var f=[];f.push.apply(f,Te("us"));for(var h=0;h0&&e[e.length-1].src&&d.push(e[e.length-1]);for(e=0;e>0;f>0;f=32&&e<=65535?d:"\ufffd";b[b.length]='"'}else if(d==="object"){b[b.length]="{";d=0;for(f in a)Object.prototype.hasOwnProperty.call(a,f)&&(e=yf(a[f],c),e!==void 0&&(d++&&(b[b.length]=","),b[b.length]=yf(f),b[b.length]=":",b[b.length]=e));b[b.length]="}"}else return}return b.join("")}};zf=/[\0-\x07\x0b\x0e-\x1f]/; +Af=/^([^"]*"([^\\"]|\\.)*")*[^"]*"([^"\\]|\\.)*[\0-\x1f]/;Bf=/^([^"]*"([^\\"]|\\.)*")*[^"]*"([^"\\]|\\.)*\\[^\\\/"bfnrtu]/;Cf=/^([^"]*"([^\\"]|\\.)*")*[^"]*"([^"\\]|\\.)*\\u([0-9a-fA-F]{0,3}[^0-9a-fA-F])/;Df=/"([^\0-\x1f\\"]|\\[\\\/"bfnrt]|\\u[0-9a-fA-F]{4})*"/g;Ef=/-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][-+]?[0-9]+)?/g;Ff=/[ \t\n\r]+/g;Gf=/[^"]:/;Hf=/""/g;If=/true|false|null/g;Jf=/00/;Kf=/[\{]([^0\}]|0[^:])/;Lf=/(^|\[)[,:]|[,:](\]|\}|[,:]|$)/;Mf=/[^\[,:][\[\{]/;Nf=/^(\{|\}|\[|\]|,|:|0)+/;Of=/\u2028/g; +Pf=/\u2029/g; +Qf=function(a){a=String(a);if(zf.test(a)||Af.test(a)||Bf.test(a)||Cf.test(a))return!1;var b=a.replace(Df,'""');b=b.replace(Ef,"0");b=b.replace(Ff,"");if(Gf.test(b))return!1;b=b.replace(Hf,"0");b=b.replace(If,"0");if(Jf.test(b)||Kf.test(b)||Lf.test(b)||Mf.test(b)||!b||(b=b.replace(Nf,"")))return!1;a=a.replace(Of,"\\u2028").replace(Pf,"\\u2029");b=void 0;try{b=of?[pf(a)]:eval("(function (var_args) {\n return Array.prototype.slice.call(arguments, 0);\n})(\n"+a+"\n)")}catch(c){return!1}return b&&b.length=== +1?b[0]:!1};Rf=function(){var a=((_.fb.document||{}).scripts||[]).length;if((mf===void 0||of===void 0||nf!==a)&&nf!==-1){mf=of=!1;nf=-1;try{try{of=!!_.fb.JSON&&_.fb.JSON.stringify.call(_.fb.JSON,{a:[3,!0,new Date(0)],c:function(){}})==='{"a":[3,true,"1970-01-01T00:00:00.000Z"]}'&&pf("true")===!0&&pf('[{"a":3}]')[0].a===3}catch(b){}mf=of&&!pf("[00]")&&!pf('"\u0007"')&&!pf('"\\0"')&&!pf('"\\v"')}finally{nf=a}}};_.Sf=function(a){if(nf===-1)return!1;Rf();return(mf?pf:Qf)(a)}; +_.Tf=function(a){if(nf!==-1)return Rf(),of?_.fb.JSON.stringify.call(_.fb.JSON,a):yf(a)};Uf=!Date.prototype.toISOString||typeof Date.prototype.toISOString!=="function"||(new Date(0)).toISOString()!=="1970-01-01T00:00:00.000Z"; +Vf=function(){var a=Date.prototype.getUTCFullYear.call(this);return[a<0?"-"+String(1E6-a).substr(1):a<=9999?String(1E4+a).substr(1):"+"+String(1E6+a).substr(1),"-",String(101+Date.prototype.getUTCMonth.call(this)).substr(1),"-",String(100+Date.prototype.getUTCDate.call(this)).substr(1),"T",String(100+Date.prototype.getUTCHours.call(this)).substr(1),":",String(100+Date.prototype.getUTCMinutes.call(this)).substr(1),":",String(100+Date.prototype.getUTCSeconds.call(this)).substr(1),".",String(1E3+Date.prototype.getUTCMilliseconds.call(this)).substr(1), +"Z"].join("")};Date.prototype.toISOString=Uf?Vf:Date.prototype.toISOString; +_.x("gadgets.json.stringify",_.Tf);_.x("gadgets.json.parse",_.Sf); +(function(){function a(e,f){if(!(e0?K.substring(1,ma):K.substring(1);K=ma>0?K.substring(ma+ +1):null;return{id:Ta,origin:K}}return null}function h(K){if(typeof K==="undefined"||K==="..")return window.parent;var ma=f(K);if(ma)return k(window.top.frames[ma.id]);K=String(K);return(ma=window.frames[K])?k(ma):(ma=document.getElementById(K))&&ma.contentWindow?ma.contentWindow:null}function k(K){return K?"postMessage"in K?K:K instanceof HTMLIFrameElement&&"contentWindow"in K&&K.contentWindow!=null&&"postMessage"in K.contentWindow?K.contentWindow:null:null}function l(K,ma){if(U[K]!==!0){typeof U[K]=== +"undefined"&&(U[K]=0);var Ta=h(K);K!==".."&&Ta==null||hb.Lb(K,ma)!==!0?U[K]!==!0&&U[K]++<10?window.setTimeout(function(){l(K,ma)},500):(S[K]=Ua,U[K]=!0):U[K]=!0}}function m(K){(K=C[K])&&K.substring(0,1)==="/"&&(K=K.substring(1,2)==="/"?document.location.protocol+K:document.location.protocol+"//"+document.location.host+K);return K}function n(K,ma,Ta){ma&&!/http(s)?:\/\/.+/.test(ma)&&(ma.indexOf("//")==0?ma=window.location.protocol+ma:ma.charAt(0)=="/"?ma=window.location.protocol+"//"+window.location.host+ +ma:ma.indexOf("://")==-1&&(ma=window.location.protocol+"//"+ma));C[K]=ma;typeof Ta!=="undefined"&&(A[K]=!!Ta)}function p(K,ma){ma=ma||"";D[K]=String(ma);l(K,ma)}function q(K){K=(K.passReferrer||"").split(":",2);P=K[0]||"none";ha=K[1]||"origin"}function r(K){String(K.useLegacyProtocol)==="true"&&(hb=ag.aB||Ua,hb.init(d,a))}function v(K,ma){function Ta(va){va=va&&va.rpc||{};q(va);var Ha=va.parentRelayUrl||"";Ha=e(Z.parent||ma)+Ha;n("..",Ha,String(va.useLegacyProtocol)==="true");r(va);p("..",K)}!Z.parent&& +ma?Ta({}):_.lf.register("rpc",null,Ta)}function u(K,ma,Ta){if(K==="..")v(Ta||Z.rpctoken||Z.ifpctok||"",ma);else a:{var va=null;if(K.charAt(0)!="/"){if(!_.gf)break a;va=document.getElementById(K);if(!va)throw Error("m`"+K);}va=va&&va.src;ma=ma||e(va);n(K,ma);ma=_.gf.Qg(va);p(K,Ta||ma.rpctoken)}}var z={},C={},A={},D={},O=0,G={},U={},Z={},S={},M={},P=null,ha=null,pa=window.top!==window.self,Ra=window.name,ub=function(){},lb=window.console,Eb=lb&&lb.log&&function(K){lb.log(K)}||function(){},Ua=function(){function K(ma){return function(){Eb(ma+ +": call ignored")}}return{fU:function(){return"noop"},jha:function(){return!0},init:K("init"),Lb:K("setup"),call:K("call")}}();_.gf&&(Z=_.gf.Qg());var Lb=!1,Mb=!1,hb=function(){if(Z.rpctx=="rmr")return ag.h0;var K=typeof window.postMessage==="function"?ag.xO:typeof window.postMessage==="object"?ag.xO:window.ActiveXObject?ag.JY?ag.JY:ag.aB:navigator.userAgent.indexOf("WebKit")>0?ag.h0:navigator.product==="Gecko"?ag.frameElement:ag.aB;K||(K=Ua);return K}();z[""]=function(){Eb("Unknown RPC service: "+ +this.s)};z.__cb=function(K,ma){var Ta=G[K];Ta&&(delete G[K],Ta.call(this,ma))};return{config:function(K){typeof K.v0==="function"&&(ub=K.v0)},register:function(K,ma){if(K==="__cb"||K==="__ack")throw Error("n");if(K==="")throw Error("o");z[K]=ma},unregister:function(K){if(K==="__cb"||K==="__ack")throw Error("p");if(K==="")throw Error("q");delete z[K]},G_:function(K){z[""]=K},D3:function(){delete z[""]},IT:function(){},call:function(K,ma,Ta,va){K=K||"..";var Ha="..";K===".."?Ha=Ra:K.charAt(0)=="/"&& +(Ha=e(window.location.href),Ha="/"+Ra+(Ha?"|"+Ha:""));++O;Ta&&(G[O]=Ta);var Y={s:ma,f:Ha,c:Ta?O:0,a:Array.prototype.slice.call(arguments,3),t:D[K],l:!!A[K]};a:if(P==="bidir"||P==="c2p"&&K===".."||P==="p2c"&&K!==".."){var wa=window.location.href;var Pa="?";if(ha==="query")Pa="#";else if(ha==="hash")break a;Pa=wa.lastIndexOf(Pa);Pa=Pa===-1?wa.length:Pa;wa=wa.substring(0,Pa)}else wa=null;wa&&(Y.r=wa);if(K===".."||f(K)!=null||document.getElementById(K))(wa=S[K])||f(K)===null||(wa=hb),ma.indexOf("legacy__")=== +0&&(wa=hb,Y.s=ma.substring(8),Y.c=Y.c?Y.c:O),Y.g=!0,Y.r=Ha,wa?(A[K]&&(wa=ag.aB),wa.call(K,Ha,Y)===!1&&(S[K]=Ua,hb.call(K,Ha,Y))):M[K]?M[K].push(Y):M[K]=[Y]},hv:m,Sj:n,oD:p,jx:u,Wn:function(K){return D[K]},ZK:function(K){delete C[K];delete A[K];delete D[K];delete U[K];delete S[K]},FU:function(){return hb.fU()},A_:function(K,ma){K.length>4?hb.Wua(K,d):c.apply(null,K.concat(ma))},B_:function(K){K.a=Array.prototype.slice.call(K.a);window.setTimeout(function(){d(K)},0)},getOrigin:e,ko:function(K){var ma= +null,Ta=m(K);Ta?ma=Ta:(Ta=f(K))?ma=Ta.origin:K==".."?ma=Z.parent:(K=document.getElementById(K))&&K.tagName.toLowerCase()==="iframe"&&(ma=K.src);return e(ma)},init:function(){hb.init(d,a)===!1&&(hb=Ua);pa?u(".."):_.lf.register("rpc",null,function(K){K=K.rpc||{};q(K);r(K)})},tP:h,Oaa:f,dna:"__ack",Zra:Ra||"..",jsa:0,isa:1,hsa:2}}();_.bg.init()};_.bg.config({v0:function(a){throw Error("r`"+a);}});_.x("gadgets.rpc.config",_.bg.config);_.x("gadgets.rpc.register",_.bg.register);_.x("gadgets.rpc.unregister",_.bg.unregister);_.x("gadgets.rpc.registerDefault",_.bg.G_);_.x("gadgets.rpc.unregisterDefault",_.bg.D3);_.x("gadgets.rpc.forceParentVerifiable",_.bg.IT);_.x("gadgets.rpc.call",_.bg.call);_.x("gadgets.rpc.getRelayUrl",_.bg.hv);_.x("gadgets.rpc.setRelayUrl",_.bg.Sj);_.x("gadgets.rpc.setAuthToken",_.bg.oD);_.x("gadgets.rpc.setupReceiver",_.bg.jx);_.x("gadgets.rpc.getAuthToken",_.bg.Wn); +_.x("gadgets.rpc.removeReceiver",_.bg.ZK);_.x("gadgets.rpc.getRelayChannel",_.bg.FU);_.x("gadgets.rpc.receive",_.bg.A_);_.x("gadgets.rpc.receiveSameDomain",_.bg.B_);_.x("gadgets.rpc.getOrigin",_.bg.getOrigin);_.x("gadgets.rpc.getTargetOrigin",_.bg.ko); +_.Lg=function(a){if(!a)return"";if(/^about:(?:blank|srcdoc)$/.test(a))return window.origin||"";a.indexOf("blob:")===0&&(a=a.substring(5));a=a.split("#")[0].split("?")[0];a=a.toLowerCase();a.indexOf("//")==0&&(a=window.location.protocol+a);/^[\w\-]*:\/\//.test(a)||(a=window.location.href);var b=a.substring(a.indexOf("://")+3),c=b.indexOf("/");c!=-1&&(b=b.substring(0,c));c=a.substring(0,a.indexOf("://"));if(!c)throw Error("s`"+a);if(c!=="http"&&c!=="https"&&c!=="chrome-extension"&&c!=="moz-extension"&& +c!=="file"&&c!=="android-app"&&c!=="chrome-search"&&c!=="chrome-untrusted"&&c!=="chrome"&&c!=="app"&&c!=="devtools")throw Error("t`"+c);a="";var d=b.indexOf(":");if(d!=-1){var e=b.substring(d+1);b=b.substring(0,d);if(c==="http"&&e!=="80"||c==="https"&&e!=="443")a=":"+e}return c+"://"+b+a}; +var Og=function(){this.blockSize=-1};var Pg=function(){this.blockSize=-1;this.blockSize=64;this.Pc=[];this.zF=[];this.Gaa=[];this.lC=[];this.lC[0]=128;for(var a=1;a>>31)&4294967295;b=a.Pc[0];c=a.Pc[1];e=a.Pc[2];for(var f=a.Pc[3],h=a.Pc[4],k,l,m=0;m<80;m++)m<40?m<20?(k=f^c&(e^f),l=1518500249):(k=c^e^f,l=1859775393):m<60?(k=c&e|f&(c|e),l=2400959708):(k=c^ +e^f,l=3395469782),k=(b<<5|b>>>27)+k+h+l+d[m]&4294967295,h=f,f=e,e=(c<<30|c>>>2)&4294967295,c=b,b=k;a.Pc[0]=a.Pc[0]+b&4294967295;a.Pc[1]=a.Pc[1]+c&4294967295;a.Pc[2]=a.Pc[2]+e&4294967295;a.Pc[3]=a.Pc[3]+f&4294967295;a.Pc[4]=a.Pc[4]+h&4294967295}; +Pg.prototype.update=function(a,b){if(a!=null){b===void 0&&(b=a.length);for(var c=b-this.blockSize,d=0,e=this.zF,f=this.ur;d=56;c--)this.zF[c]=b&255,b/=256;Qg(this,this.zF);for(c=b=0;c<5;c++)for(var d=24;d>=0;d-=8)a[b]=this.Pc[c]>>d&255,++b;return a};_.Rg=function(){this.FN=new Pg};_.g=_.Rg.prototype;_.g.reset=function(){this.FN.reset()};_.g.G3=function(a){this.FN.update(a)};_.g.DR=function(){return this.FN.digest()};_.g.Px=function(a){a=unescape(encodeURIComponent(a));for(var b=[],c=a.length,d=0;d>>1);var l=c?b.call(void 0,a[k],k,a):b(d,a[k]);l>0?e=k+1:(f=k,h=!l)}return h?e:-e-1};_.hi=function(a,b){var c={},d;for(d in a)b.call(void 0,a[d],d,a)&&(c[d]=a[d]);return c};var ii;ii=/^https?:\/\/(?:\w|[\-\.])+\.google\.(?:\w|[\-:\.])+(?:\/[^\?#]*)?\/u\/(\d)\//; +_.ji=function(a){var b=_.fi("googleapis.config/sessionIndex");"string"===typeof b&&b.length>254&&(b=null);b==null&&(b=window.__X_GOOG_AUTHUSER);"string"===typeof b&&b.length>254&&(b=null);if(b==null){var c=window.google;c&&(b=c.authuser)}"string"===typeof b&&b.length>254&&(b=null);b==null&&(a=a||window.location.href,b=_.Me(a,"authuser")||null,b==null&&(b=(b=a.match(ii))?b[1]:null));if(b==null)return null;b=String(b);b.length>254&&(b=null);return b}; +_.wi=function(){if(!_.fb.addEventListener||!Object.defineProperty)return!1;var a=!1,b=Object.defineProperty({},"passive",{get:function(){a=!0}});try{var c=function(){};_.fb.addEventListener("test",c,b);_.fb.removeEventListener("test",c,b)}catch(d){}return a}(); +var xi=function(){var a=_.Se.ms||_.Se.u;if(a)return(new URL(a)).origin};var yi=function(a){this.zT=a;this.count=this.count=0};yi.prototype.tb=function(a,b){a?this.count+=a:this.count++;this.zT&&(b===void 0||b)&&this.zT()};yi.prototype.get=function(){return this.count};yi.prototype.reset=function(){this.count=0};var Ai,Di;Ai=function(){var a=!0,b=this;a=a===void 0?!0:a;this.iz=new Map;this.sF=!1;var c=xi();c&&(this.url=c+"/js/gen_204",c=_.fi("gen204logger")||{},this.Gu=c.interval,this.AT=c.rate,this.sF=c.kva,a&&this.url&&zi(this),document.addEventListener("visibilitychange",this.flush),this.flush(),document.addEventListener("visibilitychange",function(){document.visibilityState==="hidden"&&b.flush()}),document.addEventListener("pagehide",this.flush.bind(this)))};_.Bi=function(){Ai.cY||(Ai.cY=new Ai);return Ai.cY}; +Di=function(a){var b=_.Se.dm||[];if(b&&b.length!==0){b=_.Ea(b);for(var c=b.next();!c.done;c=b.next())_.Ci(a,c.value).tb(1,!1);delete _.Se.dm;a.flush()}};_.Ci=function(a,b){a.iz.has(b)||a.iz.set(b,new yi(a.sF?void 0:function(){a.flush()}));return a.iz.get(b)}; +Ai.prototype.flush=function(){var a=this;if(this.url&&this.AT){Di(this);for(var b="",c=_.Ea(this.iz),d=c.next();!d.done;d=c.next()){var e=_.Ea(d.value);d=e.next().value;e=e.next().value;var f=e.get();f>0&&(b+=b.length>0?"&":"",b+="c=",b+=encodeURIComponent(d+":"+f),e.reset());if(b.length>1E3)break}if(b!==""&&Math.random()0&&++Oi==Ni&&_.Qe(_.De,"mousemove",Pi,"remove","de")}; +Ii=function(a){var b=new _.Rg;b.Px(a);return b.Si()};Ei=!!Fi&&typeof Fi.getRandomValues=="function";Ei||(Ji=(screen.width*screen.width+screen.height)*1E6,Hi=Ii(_.Ee.cookie+"|"+_.Ee.location+"|"+(new Date).getTime()+"|"+Math.random()),Ni=_.fi("random/maxObserveMousemove")||0,Ni!=0&&_.Re(_.De,"mousemove",Pi)); +_.Zi=function(a){var b=window;a=(a||b.location.href).match(RegExp(".*(\\?|#|&)usegapi=([^&#]+)"))||[];return"1"===decodeURIComponent(a[a.length-1]||"")}; +var ej;_.dj=function(a,b){b=(0,_.tb)(a,b);var c;(c=b>=0)&&Array.prototype.splice.call(a,b,1);return c};_.fj=function(a,b){for(var c,d,e=1;e0){this.XB--;var a=this.WA;this.WA=a.next;a.next=null}else a=this.oca();return a};kk.prototype.put=function(a){this.Yja(a);this.XB<100&&(this.XB++,a.next=this.WA,this.WA=a)};_.lk=function(a){return a};_.jj(function(a){_.lk=a});var mk=function(){this.xE=this.kt=null};mk.prototype.add=function(a,b){var c=ck.get();c.set(a,b);this.xE?this.xE.next=c:this.kt=c;this.xE=c};mk.prototype.remove=function(){var a=null;this.kt&&(a=this.kt,this.kt=this.kt.next,this.kt||(this.xE=null),a.next=null);return a};var ck=new kk(function(){return new nk},function(a){return a.reset()}),nk=function(){this.next=this.scope=this.Ph=null};nk.prototype.set=function(a,b){this.Ph=a;this.scope=b;this.next=null}; +nk.prototype.reset=function(){this.next=this.scope=this.Ph=null};var ok,dk,bk,pk;dk=!1;bk=new mk;_.qk=function(a,b){ok||pk();dk||(ok(),dk=!0);bk.add(a,b)};pk=function(){var a=Promise.resolve(void 0);ok=function(){a.then(ek)}};var tk,uk,vk,Jk,Nk,Lk,Ok;_.sk=function(a,b){this.Ea=0;this.mf=void 0;this.mq=this.Hl=this.Jb=null;this.LA=this.EG=!1;if(a!=_.gk)try{var c=this;a.call(b,function(d){rk(c,2,d)},function(d){rk(c,3,d)})}catch(d){rk(this,3,d)}};tk=function(){this.next=this.context=this.Rr=this.kw=this.Fn=null;this.uy=!1};tk.prototype.reset=function(){this.context=this.Rr=this.kw=this.Fn=null;this.uy=!1};uk=new kk(function(){return new tk},function(a){a.reset()}); +vk=function(a,b,c){var d=uk.get();d.kw=a;d.Rr=b;d.context=c;return d};_.wk=function(a){if(a instanceof _.sk)return a;var b=new _.sk(_.gk);rk(b,2,a);return b};_.xk=function(a){return new _.sk(function(b,c){c(a)})};_.zk=function(a,b,c){yk(a,b,c,null)||_.qk(_.kb(b,a))};_.Ak=function(a){return new _.sk(function(b,c){var d=a.length,e=[];if(d)for(var f=function(m,n){d--;e[m]=n;d==0&&b(e)},h=function(m){c(m)},k,l=0;l1)));h=h.next)e||(f=h);e&&(c.Ea==0&&d==1?Hk(c,b):(f?(d=f,d.next==c.mq&&(c.mq=d),d.next=d.next.next):Ik(c),Jk(c,e,3,b)))}a.Jb=null}else rk(a,3,b)},Ek=function(a,b){a.Hl||a.Ea!=2&&a.Ea!=3||Kk(a);a.mq?a.mq.next=b:a.Hl=b;a.mq=b},Dk=function(a,b,c,d){var e=vk(null,null,null);e.Fn=new _.sk(function(f,h){e.kw=b?function(k){try{var l=b.call(d,k);f(l)}catch(m){h(m)}}:f;e.Rr=c? +function(k){try{var l=c.call(d,k);l===void 0&&k instanceof _.Gk?h(k):f(l)}catch(m){h(m)}}:h});e.Fn.Jb=a;Ek(a,e);return e.Fn};_.sk.prototype.xma=function(a){this.Ea=0;rk(this,2,a)};_.sk.prototype.yma=function(a){this.Ea=0;rk(this,3,a)}; +var rk=function(a,b,c){a.Ea==0&&(a===c&&(b=3,c=new TypeError("Promise cannot resolve to itself")),a.Ea=1,yk(c,a.xma,a.yma,a)||(a.mf=c,a.Ea=b,a.Jb=null,Kk(a),b!=3||c instanceof _.Gk||Lk(a,c)))},yk=function(a,b,c,d){if(a instanceof _.sk)return Fk(a,b,c,d),!0;if(_.ik(a))return a.then(b,c,d),!0;if(_.xb(a))try{var e=a.then;if(typeof e==="function")return Mk(a,e,b,c,d),!0}catch(f){return c.call(d,f),!0}return!1},Mk=function(a,b,c,d,e){var f=!1,h=function(l){f||(f=!0,c.call(e,l))},k=function(l){f||(f=!0, +d.call(e,l))};try{b.call(a,h,k)}catch(l){k(l)}},Kk=function(a){a.EG||(a.EG=!0,_.qk(a.Kz,a))},Ik=function(a){var b=null;a.Hl&&(b=a.Hl,a.Hl=b.next,b.next=null);a.Hl||(a.mq=null);return b};_.sk.prototype.Kz=function(){for(var a;a=Ik(this);)Jk(this,a,this.Ea,this.mf);this.EG=!1};Jk=function(a,b,c,d){if(c==3&&b.Rr&&!b.uy)for(;a&&a.LA;a=a.Jb)a.LA=!1;if(b.Fn)b.Fn.Jb=null,Nk(b,c,d);else try{b.uy?b.kw.call(b.context):Nk(b,c,d)}catch(e){Ok.call(null,e)}uk.put(b)}; +Nk=function(a,b,c){b==2?a.kw.call(a.context,c):a.Rr&&a.Rr.call(a.context,c)};Lk=function(a,b){a.LA=!0;_.qk(function(){a.LA&&Ok.call(null,b)})};Ok=_.uh;_.Gk=function(a){_.nb.call(this,a);this.O_=!1};_.qb(_.Gk,_.nb);_.Gk.prototype.name="cancel";var Bk=function(a,b,c){this.promise=a;this.resolve=b;this.reject=c}; +_.Pk=function(a){return new _.sk(a)}; +var Xk=function(){this.Jx={I_:Qk?"../"+Qk:null,wz:Rk,TU:Sk,jxa:Tk,qo:Uk,bya:Vk};this.Uf=_.De;this.WZ=this.wca;this.mda=/MSIE\s*[0-8](\D|$)/.test(window.navigator.userAgent);if(this.Jx.I_){this.Uf=this.Jx.TU(this.Uf,this.Jx.I_);var a=this.Uf.document,b=a.createElement("script");b.setAttribute("type","text/javascript");b.text="window.doPostMsg=function(w,s,o) {window.setTimeout(function(){w.postMessage(s,o);},0);};";a.body.appendChild(b);this.WZ=this.Uf.doPostMsg}this.GN={};this.iO={};a=(0,_.Db)(this.dI, +this);_.Re(this.Uf,"message",a);_.He(_.Se,"RPMQ",[]).push(a);this.Uf!=this.Uf.parent&&Wk(this,this.Uf.parent,this.BJ(this.Uf.name),"*")};Xk.prototype.BJ=function(a){return'{"h":"'+escape(a)+'"}'};var Yk=function(a){var b=null;a.indexOf('{"h":"')===0&&a.indexOf('"}')===a.length-2&&(b=unescape(a.substring(6,a.length-2)));return b},Zk=function(a){if(!/^\s*{/.test(a))return!1;a=_.Sf(a);return a!==null&&typeof a==="object"&&!!a.g}; +Xk.prototype.dI=function(a){var b=String(a.data);_.Xf.debug("gapix.rpc.receive("+Tk+"): "+(!b||b.length<=512?b:b.substr(0,512)+"... ("+b.length+" bytes)"));var c=b.indexOf("!_")!==0;c||(b=b.substring(2));var d=Zk(b);if(!c&&!d){if(!d&&(c=Yk(b))){if(this.GN[c])this.GN[c]();else this.iO[c]=1;return}var e=a.origin,f=this.Jx.wz;this.mda?_.De.setTimeout(function(){f(b,e)},0):f(b,e)}};Xk.prototype.Lb=function(a,b){a===".."||this.iO[a]?(b(),delete this.iO[a]):this.GN[a]=b}; +var Wk=function(a,b,c,d){var e=Zk(c)?"":"!_";_.Xf.debug("gapix.rpc.send("+Tk+"): "+(!c||c.length<=512?c:c.substr(0,512)+"... ("+c.length+" bytes)"));a.WZ(b,e+c,d)};Xk.prototype.wca=function(a,b,c){a.postMessage(b,c)};Xk.prototype.send=function(a,b,c){(a=this.Jx.TU(this.Uf,a))&&!a.closed&&Wk(this,a,b,c)};var $k,al,bl,cl,dl,el,fl,Qk,Tk,gl,hl,il,Sk,Uk,kl,ll,ql,rl,tl,Vk,vl,ul,ml,nl,wl,Rk,xl,yl;$k=0;al=[];bl={};cl={};dl=_.De.location.href;el=_.Me(dl,"rpctoken");fl=_.Me(dl,"parent")||_.Ee.referrer;Qk=_.Me(dl,"rly");Tk=Qk||(_.De!==_.De.top||_.De.opener)&&_.De.name||"..";gl=null;hl={};il=function(){};_.jl={send:il,Lb:il,BJ:il}; +Sk=function(a,b){var c=a;b.charAt(0)=="/"&&(b=b.substring(1),c=_.De.top);if(b.length===0)return c;for(b=b.split("/");b.length;){a=b.shift();a.charAt(0)=="{"&&a.charAt(a.length-1)=="}"&&(a=a.substring(1,a.length-1));var d=a;if(d==="..")c=c==c.parent?c.opener:c.parent;else if(d!==".."&&c.frames[d]){var e=c;a=d;c=c.frames[d];if(!("postMessage"in c))if(c instanceof HTMLIFrameElement&&"contentWindow"in c)c=c.contentWindow!=null&&"postMessage"in c.contentWindow?c.contentWindow:null;else{d=null;e=_.Ea(e.document.getElementsByTagName("iframe")); +for(var f=e.next();!f.done;f=e.next())if(f=f.value,f.getAttribute("id")==a||f.getAttribute("name")==a)d=f;if(d&&"contentWindow"in d)c=d.contentWindow!=null?d.contentWindow:null;else throw Error("F`"+c+"`"+a);}}else return null}return c};Uk=function(a){return(a=bl[a])&&a.token};kl=function(a){if(a.f in{})return!1;var b=a.t,c=bl[a.r];a=a.origin;return c&&(c.token===b||!c.token&&!b)&&(a===c.origin||c.origin==="*")}; +ll=function(a){var b=a.id.split("/"),c=b[b.length-1],d=a.origin;return function(e){var f=e.origin;return e.f==c&&(d==f||d=="*")}};_.ol=function(a,b,c){a=ml(a);cl[a.name]={Ph:b,Wv:a.Wv,it:c||kl};nl()};_.pl=function(a){a=ml(a);delete cl[a.name]};ql={};rl=function(a,b){(a=ql["_"+a])&&a[1](this)&&a[0].call(this,b)};tl=function(a){var b=a.c;if(!b)return il;var c=a.r,d=a.g?"legacy__":"";return function(){var e=[].slice.call(arguments,0);e.unshift(c,d+"__cb",null,b);_.sl.apply(null,e)}}; +Vk=function(a){gl=a};vl=function(a){hl[a]||(hl[a]=_.De.setTimeout(function(){hl[a]=!1;ul(a)},0))};ul=function(a){var b=bl[a];if(b&&b.ready){var c=b.MK;for(b.MK=[];c.length;)_.jl.send(a,_.Tf(c.shift()),b.origin)}};ml=function(a){return a.indexOf("legacy__")===0?{name:a.substring(8),Wv:!0}:{name:a,Wv:!1}}; +nl=function(){for(var a=_.fi("rpc/residenceSec")||60,b=(new Date).getTime()/1E3,c,d=0;c=al[d];++d){var e=c.vp;if(!e||a>0&&b-c.timestamp>a)al.splice(d,1),--d;else{var f=e.s,h=cl[f]||cl["*"];if(h)if(al.splice(d,1),--d,e.origin=c.origin,c=tl(e),e.callback=c,h.it(e)){if(f!=="__cb"&&!!h.Wv!=!!e.g)break;e=h.Ph.apply(e,e.a);e!==void 0&&c(e)}else _.Xf.debug("gapix.rpc.rejected("+Tk+"): "+f)}}};wl=function(a,b,c){al.push({vp:a,origin:b,timestamp:(new Date).getTime()/1E3});c||nl()}; +Rk=function(a,b){a=_.Sf(a);wl(a,b,!1)};xl=function(a){for(;a.length;)wl(a.shift(),this.origin,!0);nl()};yl=function(a){var b=!1;a=a.split("|");var c=a[0];c.indexOf("/")>=0&&(b=!0);return{id:c,origin:a[1]||"*",WI:b}}; +_.zl=function(a,b,c,d){var e=yl(a);d&&(_.De.frames[e.id]=_.De.frames[e.id]||d);a=e.id;if(!bl.hasOwnProperty(a)){c=c||null;d=e.origin;if(a==="..")d=_.Lg(fl),c=c||el;else if(!e.WI){var f=_.Ee.getElementById(a);f&&(f=f.src,d=_.Lg(f),c=c||_.Me(f,"rpctoken"))}e.origin==="*"&&d||(d=e.origin);bl[a]={token:c,MK:[],origin:d,kka:b,z_:function(){var h=a;bl[h].ready=1;ul(h)}};_.jl.Lb(a,bl[a].z_)}return bl[a].z_}; +_.sl=function(a,b,c,d){a=a||"..";_.zl(a);a=a.split("|",1)[0];var e=b,f=a,h=[].slice.call(arguments,3),k=c,l=Tk,m=el,n=bl[f],p=l,q=yl(f);if(n&&f!==".."){if(q.WI){if(!(m=bl[f].kka)){m=gl?gl.substring(1).split("/"):[Tk];p=m.length-1;for(f=_.De.parent;f!==_.De.top;){var r=f.parent;if(!p--){for(var v=null,u=r.frames.length,z=0;z/g;El=/"/g;Jl=/'/g;Kl=function(a){return String(a).replace(Bl,"&").replace(Cl,"<").replace(Dl,">").replace(El,""").replace(Jl,"'")};Ll=/[\ud800-\udbff][\udc00-\udfff]|[^!-~]/g;Ml=/%([a-f]|[0-9a-fA-F][a-f])/g;Nl=/^(https?|ftp|file|chrome-extension):$/i; +Ol=function(a){a=String(a);a=a.replace(Ll,function(e){try{return encodeURIComponent(e)}catch(f){return encodeURIComponent(e.replace(/^[^%]+$/g,"\ufffd"))}}).replace(_.Oe,function(e){return e.replace(/%/g,"%25")}).replace(Ml,function(e){return e.toUpperCase()});a=a.match(_.Ne)||[];var b=_.Ie(),c=function(e){return e.replace(/\\/g,"%5C").replace(/\^/g,"%5E").replace(/`/g,"%60").replace(/\{/g,"%7B").replace(/\|/g,"%7C").replace(/\}/g,"%7D")},d=!!(a[1]||"").match(Nl);b.base=c((a[1]||"")+(a[2]||"")+(a[3]|| +(a[2]&&d?"/":"")));d=function(e){return c(e.replace(/\?/g,"%3F").replace(/#/g,"%23"))};b.query=a[5]?[d(a[5])]:[];b.Xi=a[7]?[d(a[7])]:[];return b};Pl=function(a){return a.base+(a.query.length>0?"?"+a.query.join("&"):"")+(a.Xi.length>0?"#"+a.Xi.join("&"):"")};Ql=function(a,b){var c=[];if(a)for(var d in a)if(_.Je(a,d)&&a[d]!=null){var e=b?b(a[d]):a[d];c.push(encodeURIComponent(d)+"="+encodeURIComponent(e))}return c}; +_.Rl=function(a,b,c,d){a=Ol(a);a.query.push.apply(a.query,Ql(b,d));a.Xi.push.apply(a.Xi,Ql(c,d));return Pl(a)}; +_.Sl=function(a,b){var c=Ol(b);b=c.base;c.query.length&&(b+="?"+c.query.join(""));c.Xi.length&&(b+="#"+c.Xi.join(""));var d="";b.length>2E3&&(c=b,b=b.substr(0,2E3),b=b.replace(_.Pe,""),d=c.substr(b.length));var e=a.createElement("div");a=a.createElement("a");c=Ol(b);b=c.base;c.query.length&&(b+="?"+c.query.join(""));c.Xi.length&&(b+="#"+c.Xi.join(""));_.Oc(a,new _.vc(_.Be(b)));e.appendChild(a);_.Rc(e,_.lc(e.innerHTML));b=String(e.firstChild.href);e.parentNode&&e.parentNode.removeChild(e);c=Ol(b+d); +b=c.base;c.query.length&&(b+="?"+c.query.join(""));c.Xi.length&&(b+="#"+c.Xi.join(""));return b};_.Tl=/^https?:\/\/[^\/%\\?#\s]+\/[^\s]*$/i;Vl=function(a){for(;a.firstChild;)a.removeChild(a.firstChild)};Wl=/^https?:\/\/(?:\w|[\-\.])+\.google\.(?:\w|[\-:\.])+(?:\/[^\?#]*)?\/b\/(\d{10,21})\//; +Xl=function(){var a=_.fi("googleapis.config/sessionDelegate");"string"===typeof a&&a.length>21&&(a=null);a==null&&(a=(a=window.location.href.match(Wl))?a[1]:null);if(a==null)return null;a=String(a);a.length>21&&(a=null);return a};Yl=function(){var a=_.Se.onl;if(!a){a=_.Ie();_.Se.onl=a;var b=_.Ie();a.e=function(c){var d=b[c];d&&(delete b[c],d())};a.a=function(c,d){b[c]=d};a.r=function(c){delete b[c]}}return a};Zl=function(a,b){b=b.onload;return typeof b==="function"?(Yl().a(a,b),b):null}; +$l=function(a){_.Al(/^\w+$/.test(a),"Unsupported id - "+a);return'onload="window.___jsl.onl.e("'+a+'")"'};am=function(a){Yl().r(a)};var cm,dm,hm;_.bm={allowtransparency:"true",frameborder:"0",hspace:"0",marginheight:"0",marginwidth:"0",scrolling:"no",style:"",tabindex:"0",vspace:"0",width:"100%"};cm={allowtransparency:!0,onload:!0};dm=0;_.em=function(a,b){var c=0;do var d=b.id||["I",dm++,"_",(new Date).getTime()].join("");while(a.getElementById(d)&&++c<5);_.Al(c<5,"Error creating iframe id");return d};_.fm=function(a,b){return a?b+"/"+a:""}; +_.gm=function(a,b,c,d){var e={},f={};a.documentMode&&a.documentMode<9&&(e.hostiemode=a.documentMode);_.Ke(d.queryParams||{},e);_.Ke(d.fragmentParams||{},f);var h=d.pfname;var k=_.Ie();_.fi("iframes/dropLegacyIdParam")||(k.id=c);k._gfid=c;k.parent=a.location.protocol+"//"+a.location.host;c=_.Me(a.location.href,"parent");h=h||"";!h&&c&&(h=_.Me(a.location.href,"_gfid","")||_.Me(a.location.href,"id",""),h=_.fm(h,_.Me(a.location.href,"pfname","")));h||(c=_.Sf(_.Me(a.location.href,"jcp","")))&&typeof c== +"object"&&(h=_.fm(c.id,c.pfname));k.pfname=h;d.connectWithJsonParam&&(h={},h.jcp=_.Tf(k),k=h);h=_.Me(b,"rpctoken")||e.rpctoken||f.rpctoken;h||(h=d.rpctoken||String(Math.round(_.Mi()*1E8)),k.rpctoken=h);d.rpctoken=h;_.Ke(k,d.connectWithQueryParams?e:f);k=a.location.href;a=_.Ie();(h=_.Me(k,"_bsh",_.Se.bsh))&&(a._bsh=h);(k=_.Se.dpo?_.Se.h:_.Me(k,"jsh",_.Se.h))&&(a.jsh=k);d.hintInFragment?_.Ke(a,f):_.Ke(a,e);return _.Rl(b,e,f,d.paramsSerializer)}; +hm=function(a){_.Al(!a||_.Tl.test(a),"Illegal url for new iframe - "+a)}; +_.im=function(a,b,c,d,e){hm(c.src);var f,h=Zl(d,c),k=h?$l(d):"";try{document.all&&(f=a.createElement('