{
  "name": "Project 5",
  "nodes": [
    {
      "parameters": {},
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        0,
        0
      ],
      "id": "f56e8806-c6bf-4eca-9e4d-d90307308813",
      "name": "Run Manually"
    },
    {
      "parameters": {
        "resource": "fileFolder",
        "queryString": "Wayfair Reports",
        "filter": {},
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        208,
        0
      ],
      "id": "a654c3f5-4971-42c8-87eb-4d8e07553645",
      "name": "Find Wayfair Reports Folder",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "resource": "fileFolder",
        "filter": {
          "folderId": {
            "__rl": true,
            "value": "={{ $json.id }}",
            "mode": "id"
          }
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        416,
        0
      ],
      "id": "b29857e1-ce37-461a-b5ed-697eb8c17faf",
      "name": "List Root Contents",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Identify categories (folders) and template file\n  // Note: mimeType not available, so we identify by name patterns\n  const items = $input.all();\n\n  const categories = [];\n  let templateFileId = null;\n\n  for (const item of items) {\n    const name = item.json.name || '';\n    const id = item.json.id;\n\n    // Template file ends with .html and contains 'template'\n    if (name.toLowerCase().includes('template') && name.endsWith('.html')) {\n      templateFileId = id;\n      console.log('Found template:', name);\n    }\n    // Category folders don't have file extensions\n    else if (!name.includes('.')) {\n      categories.push({\n        categoryName: name.toLowerCase().replace(/\\s+/g, '_'),\n        categoryFolderId: id\n      });\n      console.log('Found category:', name);\n    }\n  }\n\n  console.log('Total categories:', categories.length);\n  console.log('Template ID:', templateFileId);\n\n  // Return first category for simplified version\n  if (categories.length > 0) {\n    return [{\n      json: {\n        ...categories[0],\n        templateFileId\n      }\n    }];\n  }\n\n  return [];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        624,
        0
      ],
      "id": "6cae58d8-9b85-438c-86db-396ef0484b7f",
      "name": "Identify Category & Template"
    },
    {
      "parameters": {
        "operation": "download",
        "fileId": {
          "__rl": true,
          "value": "={{ $json.templateFileId }}",
          "mode": "id"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        832,
        0
      ],
      "id": "6a6e7ebc-40fa-43cc-9ac6-63eec7ad8c11",
      "name": "Download Template",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const item = $input.first();\nlet templateHtml = '';\n\nif (item.binary?.data) {\n  const buffer = await this.helpers.getBinaryDataBuffer(0, 'data');\n  templateHtml = buffer.toString('utf8'); // no 'const' - assigns to outer variable\n  console.log('Template loaded, length:', templateHtml.length);\n}\n\nconst categoryInfo = $('Identify Category & Template').first().json;\n\nreturn [{\n  json: {\n    categoryName: categoryInfo.categoryName,\n    categoryFolderId: categoryInfo.categoryFolderId,\n    templateHtml\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1040,
        0
      ],
      "id": "30d10755-3261-4b2d-8bc7-d00a4075b3ea",
      "name": "Store Template"
    },
    {
      "parameters": {
        "resource": "fileFolder",
        "filter": {
          "folderId": {
            "__rl": true,
            "value": "={{ $('Identify Category & Template').item.json.categoryFolderId }}",
            "mode": "id"
          }
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        1248,
        0
      ],
      "id": "f5c6977a-ca20-473c-8f9c-3e875283a47d",
      "name": "List Date Folders",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Get only the LATEST date folder\nconst items = $input.all();\nconst categoryInfo = $('Store Template').first().json;\n\n// Filter to date folders (YYYY-MM-DD pattern) and sort descending\nconst dateFolders = items\n  .filter(item => /^\\d{4}-\\d{2}-\\d{2}$/.test(item.json.name))\n  .map(item => ({\n    dateFolderId: item.json.id,\n    dateFolderName: item.json.name\n  }))\n  .sort((a, b) => b.dateFolderName.localeCompare(a.dateFolderName));\n\nconsole.log('Date folders found:', dateFolders.length);\nconsole.log('Latest:', dateFolders[0]?.dateFolderName);\n\n// Return only the latest one\nif (dateFolders.length > 0) {\n  return [{\n    json: {\n      ...categoryInfo,\n      ...dateFolders[0]\n    }\n  }];\n}\n\nreturn [];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1456,
        0
      ],
      "id": "bc3fca46-9901-41d6-b3b0-277c0dafcf99",
      "name": "Get Latest Date Only"
    },
    {
      "parameters": {
        "resource": "fileFolder",
        "filter": {
          "folderId": {
            "__rl": true,
            "value": "={{ $json.dateFolderId }}",
            "mode": "id"
          }
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        1664,
        0
      ],
      "id": "70105beb-0bc6-41df-b84c-06f6dc787dc2",
      "name": "List P2/P3 Files",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Identify P2 and P3 file IDs\nconst items = $input.all();\nconst context = $('Get Latest Date Only').first().json;\n\nlet p2FileId = null;\nlet p3FileId = null;\n\nfor (const item of items) {\n  const name = (item.json.name || '').toLowerCase();\n  const id = item.json.id;\n  \n  if (name.includes('p2') || name.includes('market')) {\n    p2FileId = id;\n    console.log('Found P2:', name);\n  }\n  if (name.includes('p3') || name.includes('competitor')) {\n    p3FileId = id;\n    console.log('Found P3:', name);\n  }\n}\n\nconsole.log('P2 ID:', p2FileId);\nconsole.log('P3 ID:', p3FileId);\n\nreturn [{\n  json: {\n    ...context,\n    p2FileId,\n    p3FileId,\n    hasP2: !!p2FileId,\n    hasP3: !!p3FileId\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1888,
        0
      ],
      "id": "391a1769-ef7f-4592-80a3-95bf0eac5a46",
      "name": "Identify P2 & P3 Files"
    },
    {
      "parameters": {
        "operation": "download",
        "fileId": {
          "__rl": true,
          "value": "={{ $json.p2FileId }}",
          "mode": "id"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        2080,
        -112
      ],
      "id": "2136e517-0140-451c-9b70-2495f29f149f",
      "name": "Download P2",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "download",
        "fileId": {
          "__rl": true,
          "value": "={{ $json.p3FileId }}",
          "mode": "id"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        2080,
        80
      ],
      "id": "56b65252-d13d-4f26-b56c-612731f5178f",
      "name": "Download P3",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Rename binary key from 'data' to 'p2_binary' to avoid merge conflicts\nconst items = $input.all();\n\nreturn items.map(item => {\n  const newItem = {\n    json: { ...item.json },\n    binary: {}\n  };\n  \n  if (item.binary?.data) {\n    newItem.binary.p2_binary = item.binary.data;\n    console.log('Renamed P2 binary');\n  }\n  \n  return newItem;\n});"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2288,
        -112
      ],
      "id": "c2c018d3-e397-4ef9-936c-9363833197e1",
      "name": "Rename P2 Binary"
    },
    {
      "parameters": {
        "jsCode": "// Rename binary key from 'data' to 'p3_binary' to avoid merge conflicts\nconst items = $input.all();\n\nreturn items.map(item => {\n  const newItem = {\n    json: { ...item.json },\n    binary: {}\n  };\n  \n  if (item.binary?.data) {\n    newItem.binary.p3_binary = item.binary.data;\n    console.log('Renamed P3 binary');\n  }\n  \n  return newItem;\n});"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2288,
        80
      ],
      "id": "0e099046-d65e-45be-b489-d41a230349ed",
      "name": "Rename P3 Binary"
    },
    {
      "parameters": {
        "mode": "combine",
        "combineBy": "combineByPosition",
        "options": {}
      },
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3.2,
      "position": [
        2544,
        0
      ],
      "id": "bf842c89-8d2f-498f-abaa-a7cfef2c4d24",
      "name": "Merge P2 & P3"
    },
    {
      "parameters": {
        "jsCode": "// ================================================================\n// PARSE P2 & P3 REPORTS - Complete Extraction\n// ================================================================\n\nconst cheerio = require('cheerio');\nconst item = $input.first();\n\n// Get context from earlier nodes\nconst context = $('Identify P2 & P3 Files').first().json;\n\n// Extract binary content\nlet p2Html = '';\nlet p3Html = '';\n\nconsole.log('Binary keys available:', Object.keys(item.binary || {}));\n\nif (item.binary?.p2_binary) {\n  const p2Buffer = await this.helpers.getBinaryDataBuffer(0, 'p2_binary');\n  p2Html = p2Buffer.toString('utf8');\n}\nif (item.binary?.p3_binary) {\n  const p3Buffer = await this.helpers.getBinaryDataBuffer(0, 'p3_binary');\n  p3Html = p3Buffer.toString('utf8');\n}\n\n\n// ================================================================\n// PARSE P2 (Market Trend Report)\n// ================================================================\nlet p2Data = {\n  keyInsight: '',\n  marketMetrics: { size2025: '', size2033: '', cagr: '' },\n  microSegments: [],\n  colorPalette: [],\n  risks: [],\n  recommendations: [],\n  moodboardImages: [],\n  attributeBars: { materials: [], sizes: [], colors: [], prices: [] }\n};\n\ntry {\n  if (p2Html) {\n    const $p2 = cheerio.load(p2Html);\n    \n    // Key Insight\n    p2Data.keyInsight = $p2('.key-insight p').first().text().trim() ||\n                        $p2('.summary-hero .key-insight p').first().text().trim() ||\n                        $p2('.executive-summary p').first().text().trim();\n    console.log('P2 Key Insight:', p2Data.keyInsight.substring(0, 100));\n    \n    // Market Metrics - look for profile-card elements\n    $p2('.profile-card').each((i, el) => {\n      const heading = $p2(el).find('h4').text().toLowerCase();\n      const value = $p2(el).find('p').first().text().trim();\n      \n      if (heading.includes('market size') && heading.includes('2025')) {\n        p2Data.marketMetrics.size2025 = value;\n      } else if (heading.includes('projected') && heading.includes('2033')) {\n        p2Data.marketMetrics.size2033 = value;\n      } else if (heading.includes('cagr')) {\n        p2Data.marketMetrics.cagr = value;\n      }\n    });\n    console.log('P2 Market Metrics:', JSON.stringify(p2Data.marketMetrics));\n    \n    // Micro-Segments\n    $p2('.segment-card').each((i, el) => {\n      const name = $p2(el).find('h4').first().text().trim();\n      const tier = $p2(el).find('.segment-badge').text().trim();\n      const description = $p2(el).find('.segment-description, p').first().text().trim();\n      const metaText = $p2(el).find('.segment-meta').text();\n      \n      // Extract colors and use cases from meta\n      const colorsMatch = metaText.match(/\ud83c\udfa8\\s*([^\ud83c\udfe0]+)/);\n      const useCasesMatch = metaText.match(/\ud83c\udfe0\\s*(.+)/);\n      \n      if (name) {\n        p2Data.microSegments.push({\n          name: name.replace(/^\\d+\\.\\s*/, ''),\n          tier: tier || 'Emerging',\n          description: description.substring(0, 300),\n          colors: colorsMatch?.[1]?.trim() || '',\n          useCases: useCasesMatch?.[1]?.trim() || ''\n        });\n      }\n    });\n    console.log('P2 Segments found:', p2Data.microSegments.length);\n    \n    // Color Palette\n    $p2('.color-swatch, .color-card').each((i, el) => {\n      const style = $p2(el).attr('style') || '';\n      const innerStyle = $p2(el).find('[style*=\"background\"]').attr('style') || '';\n      const allStyles = style + ' ' + innerStyle;\n      const hexMatch = allStyles.match(/#[A-Fa-f0-9]{6}/);\n      const name = $p2(el).find('.swatch-label, .color-name').text().trim() || \n                   $p2(el).text().trim().split('\\n')[0];\n      \n      if (hexMatch && p2Data.colorPalette.length < 6) {\n        p2Data.colorPalette.push({\n          hex: hexMatch[0],\n          name: name.substring(0, 30) || `Color ${i + 1}`\n        });\n      }\n    });\n    console.log('P2 Colors found:', p2Data.colorPalette.length);\n    \n    // Risks\n    $p2('.risk-card').each((i, el) => {\n      const title = $p2(el).find('h4, .risk-title').first().text().trim();\n      const className = $p2(el).attr('class') || '';\n      let severity = 'medium';\n      if (className.includes('high') || className.includes('risk-high')) severity = 'high';\n      else if (className.includes('low') || className.includes('risk-low')) severity = 'low';\n      \n      const description = $p2(el).find('p, .risk-description').first().text().trim();\n      const mitigation = $p2(el).find('.risk-mitigation').text().replace(/Mitigation:?/gi, '').trim();\n      \n      if (title) {\n        p2Data.risks.push({ title, severity, description: description.substring(0, 200), mitigation });\n      }\n    });\n    console.log('P2 Risks found:', p2Data.risks.length);\n    \n    // Recommendations\n    $p2('.rec-item, .recommendation-card').each((i, el) => {\n      const title = $p2(el).find('h4, strong').first().text().trim();\n      const description = $p2(el).find('p').first().text().trim();\n      const impact = $p2(el).find('.rec-impact').text().trim();\n      \n      if (title && p2Data.recommendations.length < 5) {\n        p2Data.recommendations.push({ title, description: description.substring(0, 200), impact });\n      }\n    });\n    console.log('P2 Recommendations found:', p2Data.recommendations.length);\n    \n    // Moodboard Images (base64)\n    $p2('img').each((i, el) => {\n      const src = $p2(el).attr('src');\n      if (src?.startsWith('data:image') && p2Data.moodboardImages.length < 4) {\n        p2Data.moodboardImages.push(src);\n      }\n    });\n    console.log('P2 Moodboard images found:', p2Data.moodboardImages.length);\n    \n  // Attribute Distribution Bars - FIXED selectors\n  $p2('.attribute-card').each((i, card) => {\n    const cardTitle = $p2(card).find('h3').first().text().toLowerCase();\n    const bars = [];\n\n    $p2(card).find('.data-row').each((j, row) => {\n      const label = $p2(row).find('.label').text().trim();\n      const value = $p2(row).find('.value').text().trim();\n      const barStyle = $p2(row).find('.bar').attr('style') || '';\n      const widthMatch = barStyle.match(/([\\d.]+)%/);\n\n      if (label) {\n        bars.push({\n          label,\n          value: value || '',\n          width: widthMatch ? parseFloat(widthMatch[1]) : 0\n        });\n      }\n    });\n\n    if (cardTitle.includes('material')) {\n      p2Data.attributeBars.materials = bars;\n    } else if (cardTitle.includes('size')) {\n      p2Data.attributeBars.sizes = bars;\n    } else if (cardTitle.includes('color') || cardTitle.includes('pattern')) {\n      p2Data.attributeBars.colors = bars;\n    } else if (cardTitle.includes('price')) {\n      p2Data.attributeBars.prices = bars;\n    }\n  });\n  console.log('P2 Attribute bars - materials:', p2Data.attributeBars.materials.length,\n              ', sizes:', p2Data.attributeBars.sizes.length,\n              ', colors:', p2Data.attributeBars.colors.length);\n  }\n} catch (e) {\n  console.error('P2 Parse Error:', e.message);\n}\n\n// ================================================================\n// PARSE P3 (Competitor Analysis Report)\n// ================================================================\nlet p3Data = {\n  keyInsight: '',\n  scope: { amazonProducts: 0, walmartProducts: 0, wayfairProducts: 0 },\n  pricePositioning: {\n    wayfair: { avg: '', min: '', max: '' },\n    amazon: { avg: '', min: '', max: '' },\n    walmart: { avg: '', min: '', max: '' }\n  },\n  comparisonTable: [],\n  priceBands: { budget: {}, mid: {}, premium: {} },\n  priceGaps: [],\n  opportunities: [],\n  quickWins: [],\n  strategicInitiatives: [],\n  suppliers: [],\n  discountTiers: []\n};\n\ntry {\n  if (p3Html) {\n    const $p3 = cheerio.load(p3Html);\n    \n    // Key Insight\n    p3Data.keyInsight = $p3('.key-insight p').first().text().trim();\n    console.log('P3 Key Insight:', p3Data.keyInsight.substring(0, 100));\n    \n    // Scope - Product Counts\n    const scopeText = $p3('.scope-card, .scope-section').text();\n    const amazonMatch = scopeText.match(/Amazon[^\\d]*(\\d+)/i);\n    const walmartMatch = scopeText.match(/Walmart[^\\d]*(\\d+)/i);\n    const wayfairMatch = scopeText.match(/Wayfair[^\\d]*(\\d+)/i);\n    if (amazonMatch) p3Data.scope.amazonProducts = parseInt(amazonMatch[1]);\n    if (walmartMatch) p3Data.scope.walmartProducts = parseInt(walmartMatch[1]);\n    if (wayfairMatch) p3Data.scope.wayfairProducts = parseInt(wayfairMatch[1]);\n    console.log('P3 Scope:', JSON.stringify(p3Data.scope));\n    \n    // Price Positioning - from comparison table\n    $p3('.comparison-table tbody tr').each((i, row) => {\n      const cells = $p3(row).find('td');\n      const attribute = $p3(cells[0]).text().toLowerCase();\n      \n      if (attribute.includes('price')) {\n        // Parse Wayfair prices\n        const wayfairText = $p3(cells[1]).text();\n        const wayfairAvg = wayfairText.match(/Avg:\\s*\\$([\\d,.]+)/i);\n        const wayfairMin = wayfairText.match(/Min:\\s*\\$([\\d,.]+)/i);\n        const wayfairMax = wayfairText.match(/Max:\\s*\\$([\\d,.]+)/i);\n        if (wayfairAvg) p3Data.pricePositioning.wayfair.avg = '$' + wayfairAvg[1];\n        if (wayfairMin) p3Data.pricePositioning.wayfair.min = '$' + wayfairMin[1];\n        if (wayfairMax) p3Data.pricePositioning.wayfair.max = '$' + wayfairMax[1];\n        \n        // Parse Amazon prices\n        const amazonText = $p3(cells[2]).text();\n        const amazonAvg = amazonText.match(/Avg:\\s*\\$([\\d,.]+)/i);\n        const amazonMin = amazonText.match(/Min:\\s*\\$([\\d,.]+)/i);\n        const amazonMax = amazonText.match(/Max:\\s*\\$([\\d,.]+)/i);\n        if (amazonAvg) p3Data.pricePositioning.amazon.avg = '$' + amazonAvg[1];\n        if (amazonMin) p3Data.pricePositioning.amazon.min = '$' + amazonMin[1];\n        if (amazonMax) p3Data.pricePositioning.amazon.max = '$' + amazonMax[1];\n        \n        // Parse Walmart prices\n        const walmartText = $p3(cells[3]).text();\n        const walmartAvg = walmartText.match(/Avg:\\s*\\$([\\d,.]+)/i);\n        const walmartMin = walmartText.match(/Min:\\s*\\$([\\d,.]+)/i);\n        const walmartMax = walmartText.match(/Max:\\s*\\$([\\d,.]+)/i);\n        if (walmartAvg) p3Data.pricePositioning.walmart.avg = '$' + walmartAvg[1];\n        if (walmartMin) p3Data.pricePositioning.walmart.min = '$' + walmartMin[1];\n        if (walmartMax) p3Data.pricePositioning.walmart.max = '$' + walmartMax[1];\n      }\n    });\n    console.log('P3 Price Positioning:', JSON.stringify(p3Data.pricePositioning));\n    \n    // Comparison Table\n    $p3('.comparison-table tbody tr').each((i, row) => {\n      const cells = $p3(row).find('td');\n      if (cells.length >= 5) {\n        const attribute = $p3(cells[0]).text().trim();\n        const wayfair = $p3(cells[1]).text().trim().substring(0, 200);\n        const amazon = $p3(cells[2]).text().trim().substring(0, 200);\n        const walmart = $p3(cells[3]).text().trim().substring(0, 200);\n        const winner = $p3(cells[4]).text().trim();\n        \n        if (attribute) {\n          p3Data.comparisonTable.push({ attribute, wayfair, amazon, walmart, winner });\n        }\n      }\n    });\n    console.log('P3 Comparison rows:', p3Data.comparisonTable.length);\n    \n    // Price Bands\n    $p3('.band').each((i, el) => {\n      const text = $p3(el).text();\n      const values = text.match(/W:\\s*(\\d+)\\s*\\|\\s*A:\\s*(\\d+)\\s*\\|\\s*Wm:\\s*(\\d+)/i);\n      \n      if (text.toLowerCase().includes('budget') && values) {\n        p3Data.priceBands.budget = { wayfair: values[1], amazon: values[2], walmart: values[3] };\n      } else if (text.toLowerCase().includes('mid') && values) {\n        p3Data.priceBands.mid = { wayfair: values[1], amazon: values[2], walmart: values[3] };\n      } else if (text.toLowerCase().includes('premium') && values) {\n        p3Data.priceBands.premium = { wayfair: values[1], amazon: values[2], walmart: values[3] };\n      }\n    });\n    console.log('P3 Price Bands:', JSON.stringify(p3Data.priceBands));\n    \n    // Price Gaps Heatmap\n    $p3('.gap').each((i, el) => {\n      const range = $p3(el).find('span').first().text().trim();\n      const description = $p3(el).find('span').last().text().trim();\n      const className = $p3(el).attr('class') || '';\n      let level = 'moderate';\n      if (className.includes('hot')) level = 'hot';\n      else if (className.includes('warm')) level = 'warm';\n      else if (className.includes('cool') || className.includes('open')) level = 'open';\n      \n      if (range) {\n        p3Data.priceGaps.push({ range, description, level });\n      }\n    });\n    console.log('P3 Price Gaps:', p3Data.priceGaps.length);\n    \n    // Opportunities\n    $p3('.whitespace-opportunities .opportunity-card, .opportunity-cards .opportunity-card').each((i, el) => {\n      const title = $p3(el).find('h4').text().replace(/[\ud83c\udfaf\u26a1\ud83d\udcca\ud83d\udca1\ud83d\udd25]/g, '').trim();\n      const description = $p3(el).find('p').first().text().trim();\n      const className = $p3(el).attr('class') || '';\n      const priority = className.includes('high') ? 'high' : (className.includes('low') ? 'low' : 'medium');\n      \n      if (title && p3Data.opportunities.length < 6) {\n        p3Data.opportunities.push({ title, description: description.substring(0, 250), priority });\n      }\n    });\n    console.log('P3 Opportunities:', p3Data.opportunities.length);\n    \n    // Quick Wins\n    $p3('.quick-wins .rec-card').each((i, el) => {\n      const title = $p3(el).find('h4').text().replace(/^\\d+\\.\\s*/, '').trim();\n      const description = $p3(el).find('p').first().text().trim();\n      const priority = $p3(el).attr('class')?.includes('high') ? 'high' : 'medium';\n      \n      if (title) {\n        p3Data.quickWins.push({ title, description: description.substring(0, 200), priority });\n      }\n    });\n    console.log('P3 Quick Wins:', p3Data.quickWins.length);\n    \n    // Strategic Initiatives\n    $p3('.strategic-plays .rec-card, .strategic-initiatives .rec-card').each((i, el) => {\n      const title = $p3(el).find('h4').text().replace(/^\\d+\\.\\s*/, '').trim();\n      const description = $p3(el).find('p').first().text().trim();\n      const priority = $p3(el).attr('class')?.includes('high') ? 'high' : 'medium';\n      \n      if (title) {\n        p3Data.strategicInitiatives.push({ title, description: description.substring(0, 200), priority });\n      }\n    });\n    console.log('P3 Strategic Initiatives:', p3Data.strategicInitiatives.length);\n    \n    // Suppliers\n    $p3('.supplier-identification table tbody tr, .suppliers-observed table tbody tr').each((i, row) => {\n      const cells = $p3(row).find('td');\n      if (cells.length >= 4) {\n        const name = $p3(cells[0]).text().trim();\n        const platform = $p3(cells[1]).text().trim();\n        \n        // Skip if it looks like a product row\n        if (name.length > 50 || platform.startsWith('$')) return;\n        \n        if (name && p3Data.suppliers.length < 10) {\n          p3Data.suppliers.push({\n            name,\n            platform,\n            knownFor: $p3(cells[2]).text().trim().substring(0, 100),\n            priceRange: $p3(cells[3]).text().trim(),\n            website: $p3(cells[4])?.find('a').attr('href') || ''\n          });\n        }\n      }\n    });\n    console.log('P3 Suppliers:', p3Data.suppliers.length);\n    \n    // Discount Tiers\n    $p3('.discount-tier').each((i, el) => {\n      const label = $p3(el).find('span').first().text().trim();\n      const values = $p3(el).find('span').last().text().trim();\n      const match = values.match(/W:\\s*(\\d+)\\s*\\|\\s*Wm:\\s*(\\d+)/i);\n      \n      if (label && match) {\n        p3Data.discountTiers.push({\n          label,\n          wayfair: parseInt(match[1]),\n          walmart: parseInt(match[2])\n        });\n      }\n    });\n    console.log('P3 Discount Tiers:', p3Data.discountTiers.length);\n  }\n} catch (e) {\n  console.error('P3 Parse Error:', e.message);\n}\n\n// Return combined data\nreturn [{\n  json: {\n    categoryName: context.categoryName,\n    dateFolderName: context.dateFolderName,\n    templateHtml: context.templateHtml,\n    p2Data,\n    p3Data\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2752,
        0
      ],
      "id": "1481c570-79c8-4b5e-95a2-de433ed10868",
      "name": "Parse P2 & P3 Reports"
    },
    {
      "parameters": {
        "jsCode": "// ================================================================\n// BUILD COMPLETE DASHBOARD HTML\n// ================================================================\n\nconst data = $input.first().json;\nconst { categoryName, dateFolderName, templateHtml, p2Data, p3Data } = data;\n\nlet html = templateHtml;\n\n// Helper function for safe replacement\nconst replace = (placeholder, value) => {\n  html = html.replace(new RegExp(placeholder.replace(/[{}]/g, '\\\\$&'), 'g'), value || '');\n};\n\n// ================================================================\n// BASIC INFO\n// ================================================================\nconst categoryTitle = categoryName.replace(/_/g, ' ').replace(/\\b\\w/g, l => l.toUpperCase());\nreplace('{{CATEGORY_TITLE}}', categoryTitle);\nreplace('{{CATEGORY_NAME}}', categoryTitle);\nreplace('{{REPORT_DATE}}', dateFolderName);\nreplace('{{GENERATED_AT}}', new Date().toISOString().split('T')[0]);\n\n// Product counts\nconst amazonProducts = p3Data.scope.amazonProducts || 0;\nconst walmartProducts = p3Data.scope.walmartProducts || 0;\nconst wayfairProducts = p3Data.scope.wayfairProducts || 0;\nconst totalProducts = amazonProducts + walmartProducts + wayfairProducts;\n\nreplace('{{AMAZON_PRODUCTS}}', amazonProducts.toString());\nreplace('{{WALMART_PRODUCTS}}', walmartProducts.toString());\nreplace('{{WAYFAIR_PRODUCTS}}', wayfairProducts.toString());\nreplace('{{TOTAL_PRODUCTS}}', totalProducts.toString());\n\n// ================================================================\n// KEY INSIGHTS\n// ================================================================\nreplace('{{TREND_KEY_INSIGHT}}', p2Data.keyInsight || 'Market trend data not available.');\nreplace('{{COMPETITIVE_KEY_INSIGHT}}', p3Data.keyInsight || 'Competitive analysis data not available.');\n\n// ================================================================\n// MARKET METRICS (P2)\n// ================================================================\nreplace('{{MARKET_SIZE_2025}}', p2Data.marketMetrics.size2025 || 'N/A');\nreplace('{{MARKET_SIZE_2033}}', p2Data.marketMetrics.size2033 || 'N/A');\nreplace('{{MARKET_CAGR}}', p2Data.marketMetrics.cagr || 'N/A');\n\n// ================================================================\n// TARGET SEGMENT (First segment from P2)\n// ================================================================\nconst targetSegment = p2Data.microSegments[0] || {};\nreplace('{{TARGET_SEGMENT_NAME}}', targetSegment.name || 'Emerging Segment');\nreplace('{{TARGET_SEGMENT_TIER}}', targetSegment.tier || 'Tier 1');\nreplace('{{TARGET_SEGMENT_USE_CASES}}', targetSegment.useCases || 'Various applications');\n\n// ================================================================\n// PRICE POSITIONING (P3)\n// ================================================================\nreplace('{{WAYFAIR_AVG_PRICE}}', p3Data.pricePositioning.wayfair.avg || 'N/A');\nreplace('{{WAYFAIR_MIN_PRICE}}', p3Data.pricePositioning.wayfair.min || 'N/A');\nreplace('{{WAYFAIR_MAX_PRICE}}', p3Data.pricePositioning.wayfair.max || 'N/A');\nreplace('{{AMAZON_AVG_PRICE}}', p3Data.pricePositioning.amazon.avg || 'N/A');\nreplace('{{AMAZON_MIN_PRICE}}', p3Data.pricePositioning.amazon.min || 'N/A');\nreplace('{{AMAZON_MAX_PRICE}}', p3Data.pricePositioning.amazon.max || 'N/A');\nreplace('{{WALMART_AVG_PRICE}}', p3Data.pricePositioning.walmart.avg || 'N/A');\nreplace('{{WALMART_MIN_PRICE}}', p3Data.pricePositioning.walmart.min || 'N/A');\nreplace('{{WALMART_MAX_PRICE}}', p3Data.pricePositioning.walmart.max || 'N/A');\n\n// ================================================================\n// PRICE BANDS (P3)\n// ================================================================\nreplace('{{BUDGET_WAYFAIR}}', p3Data.priceBands.budget?.wayfair || '0');\nreplace('{{BUDGET_AMAZON}}', p3Data.priceBands.budget?.amazon || '0');\nreplace('{{BUDGET_WALMART}}', p3Data.priceBands.budget?.walmart || '0');\nreplace('{{MID_WAYFAIR}}', p3Data.priceBands.mid?.wayfair || '0');\nreplace('{{MID_AMAZON}}', p3Data.priceBands.mid?.amazon || '0');\nreplace('{{MID_WALMART}}', p3Data.priceBands.mid?.walmart || '0');\nreplace('{{PREMIUM_WAYFAIR}}', p3Data.priceBands.premium?.wayfair || '0');\nreplace('{{PREMIUM_AMAZON}}', p3Data.priceBands.premium?.amazon || '0');\nreplace('{{PREMIUM_WALMART}}', p3Data.priceBands.premium?.walmart || '0');\n\n// ================================================================\n// RISK COUNTS (P2)\n// ================================================================\nconst highRisks = p2Data.risks.filter(r => r.severity === 'high').length;\nconst mediumRisks = p2Data.risks.filter(r => r.severity === 'medium').length;\nconst lowRisks = p2Data.risks.filter(r => r.severity === 'low').length;\nreplace('{{HIGH_RISKS}}', highRisks.toString());\nreplace('{{MEDIUM_RISKS}}', mediumRisks.toString());\nreplace('{{LOW_RISKS}}', lowRisks.toString());\n\n// ================================================================\n// SEGMENTS HTML (P2)\n// ================================================================\nlet segmentsHtml = '';\np2Data.microSegments.forEach((seg, i) => {\n  segmentsHtml += `\n    <div class=\"segment-card\">\n      <div class=\"segment-header\">\n        <span class=\"segment-number\">${i + 1}</span>\n        <div class=\"segment-title\">${seg.name}</div>\n        <span class=\"badge badge-${seg.tier === 'Tier 1' ? 'success' : 'info'}\">${seg.tier}</span>\n      </div>\n      <p class=\"segment-description\">${seg.description}</p>\n      <div class=\"segment-meta\">\n        ${seg.colors ? `<span>\ud83c\udfa8 ${seg.colors}</span>` : ''}\n        ${seg.useCases ? `<span>\ud83c\udfe0 ${seg.useCases}</span>` : ''}\n      </div>\n    </div>`;\n});\nreplace('{{SEGMENTS_HTML}}', segmentsHtml || '<p class=\"empty-state\">No segment data available</p>');\n\n// ================================================================\n// COLOR PALETTE HTML (P2)\n// ================================================================\nlet colorPaletteHtml = '';\np2Data.colorPalette.forEach(color => {\n  colorPaletteHtml += `\n    <div class=\"color-swatch\">\n      <div class=\"swatch-color\" style=\"background-color: ${color.hex};\"></div>\n      <div class=\"swatch-info\">\n        <span class=\"swatch-name\">${color.name}</span>\n        <span class=\"swatch-hex\">${color.hex}</span>\n      </div>\n    </div>`;\n});\nreplace('{{COLOR_PALETTE_HTML}}', colorPaletteHtml || '<p class=\"empty-state\">No color data available</p>');\n\n// ================================================================\n// MOODBOARD HTML (P2)\n// ================================================================\nlet moodboardHtml = '';\np2Data.moodboardImages.forEach((src, i) => {\n  moodboardHtml += `<div class=\"mood-image\"><img src=\"${src}\" alt=\"Mood ${i + 1}\" loading=\"lazy\"></div>`;\n});\nreplace('{{MOODBOARD_HTML}}', moodboardHtml || '<p class=\"empty-state\">No moodboard images available</p>');\n\n// ================================================================\n// RISKS HTML (P2)\n// ================================================================\nlet risksHtml = '';\np2Data.risks.forEach(risk => {\n  risksHtml += `\n    <div class=\"risk-card risk-${risk.severity}\">\n      <div class=\"risk-header\">\n        <h4>${risk.title}</h4>\n        <span class=\"badge badge-${risk.severity === 'high' ? 'danger' : (risk.severity === 'low' ? 'success' : 'warning')}\">${risk.severity}</span>\n      </div>\n      <p>${risk.description}</p>\n      ${risk.mitigation ? `<div class=\"risk-mitigation\"><strong>Mitigation:</strong> ${risk.mitigation}</div>` : ''}\n    </div>`;\n});\nreplace('{{RISKS_HTML}}', risksHtml || '<p class=\"empty-state\">No risk data available</p>');\n\n// ================================================================\n// COMPARISON TABLE HTML (P3)\n// ================================================================\nlet comparisonTableHtml = '';\np3Data.comparisonTable.forEach(row => {\n  const winnerClass = row.winner.toLowerCase().includes('wayfair') ? 'winner-wayfair' : \n                      (row.winner.toLowerCase().includes('amazon') ? 'winner-amazon' : 'winner-walmart');\n  comparisonTableHtml += `\n    <tr>\n      <td><strong>${row.attribute}</strong></td>\n      <td>${row.wayfair}</td>\n      <td>${row.amazon}</td>\n      <td>${row.walmart}</td>\n      <td class=\"${winnerClass}\">${row.winner}</td>\n    </tr>`;\n});\nreplace('{{COMPARISON_TABLE_HTML}}', comparisonTableHtml || '<tr><td colspan=\"5\">No comparison data available</td></tr>');\n\n// ================================================================\n// PRICE GAPS HTML (P3)\n// ================================================================\nlet priceGapsHtml = '';\np3Data.priceGaps.forEach(gap => {\n  priceGapsHtml += `\n    <div class=\"price-gap gap-${gap.level}\">\n      <span class=\"gap-range\">${gap.range}</span>\n      <span class=\"gap-description\">${gap.description}</span>\n    </div>`;\n});\nreplace('{{PRICE_GAPS_HTML}}', priceGapsHtml || '<p class=\"empty-state\">No price gap data available</p>');\n\n// ================================================================\n// OPPORTUNITIES HTML (P3)\n// ================================================================\nlet opportunitiesHtml = '';\np3Data.opportunities.forEach(opp => {\n  opportunitiesHtml += `\n    <div class=\"opportunity-card priority-${opp.priority}\">\n      <h4>${opp.title}</h4>\n      <p>${opp.description}</p>\n      <span class=\"badge badge-${opp.priority === 'high' ? 'danger' : 'warning'}\">${opp.priority} priority</span>\n    </div>`;\n});\nreplace('{{OPPORTUNITIES_HTML}}', opportunitiesHtml || '<p class=\"empty-state\">No opportunity data available</p>');\n\n// ================================================================\n// QUICK WINS HTML (P3)\n// ================================================================\nlet quickWinsHtml = '';\np3Data.quickWins.forEach((win, i) => {\n  quickWinsHtml += `\n    <div class=\"action-card priority-${win.priority}\">\n      <div class=\"action-number\">${i + 1}</div>\n      <div class=\"action-content\">\n        <h4>${win.title}</h4>\n        <p>${win.description}</p>\n      </div>\n    </div>`;\n});\nreplace('{{QUICK_WINS_HTML}}', quickWinsHtml || '<p class=\"empty-state\">No quick wins available</p>');\n\n// ================================================================\n// STRATEGIC INITIATIVES HTML (P3)\n// ================================================================\nlet strategicHtml = '';\np3Data.strategicInitiatives.forEach((init, i) => {\n  strategicHtml += `\n    <div class=\"initiative-card priority-${init.priority}\">\n      <div class=\"initiative-number\">${i + 1}</div>\n      <div class=\"initiative-content\">\n        <h4>${init.title}</h4>\n        <p>${init.description}</p>\n      </div>\n    </div>`;\n});\nreplace('{{STRATEGIC_INITIATIVES_HTML}}', strategicHtml || '<p class=\"empty-state\">No strategic initiatives available</p>');\n\n// ================================================================\n// SUPPLIERS HTML (P3)\n// ================================================================\nlet suppliersHtml = '';\np3Data.suppliers.forEach(supplier => {\n  suppliersHtml += `\n    <tr>\n      <td><strong>${supplier.name}</strong></td>\n      <td><span class=\"badge badge-${supplier.platform.toLowerCase() === 'amazon' ? 'warning' : 'info'}\">${supplier.platform}</span></td>\n      <td>${supplier.knownFor}</td>\n      <td>${supplier.priceRange}</td>\n      <td>${supplier.website ? `<a href=\"${supplier.website}\" target=\"_blank\">Visit</a>` : '-'}</td>\n    </tr>`;\n});\nreplace('{{SUPPLIERS_HTML}}', suppliersHtml || '<tr><td colspan=\"5\">No supplier data available</td></tr>');\n\n// ================================================================\n// SUPPLIER CARDS HTML (for Key Suppliers section)\n// ================================================================\nlet supplierChipsHtml = '';\np3Data.suppliers.slice(0, 5).forEach(supplier => {\n  const platformClass = supplier.platform.toLowerCase();\n  const searchUrl = platformClass === 'amazon' \n    ? `https://www.amazon.com/s?k=${encodeURIComponent(supplier.name)}` \n    : platformClass === 'walmart' \n      ? `https://www.walmart.com/search?q=${encodeURIComponent(supplier.name)}`\n      : `https://www.wayfair.com/keyword.html?keyword=${encodeURIComponent(supplier.name)}`;\n  supplierChipsHtml += `<a href=\"${searchUrl}\" target=\"_blank\" class=\"supplier-card\"><span class=\"supplier-name\">${supplier.name}</span><span class=\"platform ${platformClass}\">${supplier.platform}</span></a>`;\n});\nreplace('{{SUPPLIER_CHIPS_HTML}}', supplierChipsHtml || '<div class=\"empty-state\">No suppliers found</div>');\n\n// ================================================================\n// ATTRIBUTE BARS HTML (P2)\n// ================================================================\nconst buildBarsHtml = (bars) => {\n  if (!bars || bars.length === 0) return '<p class=\"empty-state\">No data available</p>';\n  return bars.map(bar => `\n    <div class=\"bar-item\">\n      <div class=\"bar-label\">${bar.label}</div>\n      <div class=\"bar-track\">\n        <div class=\"bar-fill\" style=\"width: ${bar.width}%;\"></div>\n      </div>\n      <div class=\"bar-value\">${bar.value}</div>\n    </div>`).join('');\n};\n\nreplace('{{MATERIALS_BARS_HTML}}', buildBarsHtml(p2Data.attributeBars.materials));\nreplace('{{SIZES_BARS_HTML}}', buildBarsHtml(p2Data.attributeBars.sizes));\nreplace('{{COLORS_BARS_HTML}}', buildBarsHtml(p2Data.attributeBars.colors));\nreplace('{{PRICES_BARS_HTML}}', buildBarsHtml(p2Data.attributeBars.prices));\n\n// ================================================================\n// DISCOUNT TIERS HTML (P3)\n// ================================================================\nlet discountTiersHtml = '';\np3Data.discountTiers.forEach(tier => {\n  discountTiersHtml += `\n    <div class=\"discount-tier\">\n      <span class=\"tier-label\">${tier.label}</span>\n      <span class=\"tier-values\">W: ${tier.wayfair} | Wm: ${tier.walmart}</span>\n    </div>`;\n});\nreplace('{{DISCOUNT_TIERS_HTML}}', discountTiersHtml || '<p class=\"empty-state\">No discount data available</p>');\n\n// ================================================================\n// ALERTS HTML (from risks and opportunities)\n// ================================================================\nlet alertsHtml = '';\nconst alertRisks = p2Data.risks.filter(r => r.severity === 'high').slice(0, 2);\nconst alertOpps = p3Data.opportunities.slice(0, 1);\nalertRisks.forEach(risk => {\n  alertsHtml += `<div class=\"alert-card high\"><div class=\"alert-type\">Risk Alert</div><h4>${risk.title}</h4><p>${risk.description.substring(0, 100)}...</p></div>`;\n});\nalertOpps.forEach(opp => {\n  alertsHtml += `<div class=\"alert-card opportunity\"><div class=\"alert-type\">Opportunity</div><h4>${opp.title}</h4><p>${opp.description.substring(0, 100)}...</p></div>`;\n});\nreplace('{{ALERTS_HTML}}', alertsHtml || '<div class=\"alert-card medium\"><div class=\"alert-type\">Info</div><h4>No alerts</h4><p>All metrics within normal range</p></div>');\n\n// ================================================================\n// TOP ACTIONS HTML\n// ================================================================\nlet topActionsHtml = '';\np3Data.quickWins.slice(0, 3).forEach((win, i) => {\n  topActionsHtml += `<div class=\"quick-action\"><span class=\"action-num\">${i + 1}</span><span class=\"action-text\">${win.title}</span></div>`;\n});\nreplace('{{TOP_ACTIONS_HTML}}', topActionsHtml || '<div class=\"quick-action\"><span class=\"action-num\">!</span><span class=\"action-text\">Review full analysis for recommendations</span></div>');\n\n// ================================================================\n// TREND RECOMMENDATIONS HTML (P2)\n// ================================================================\nlet trendRecsHtml = '';\np2Data.recommendations.forEach((rec, i) => {\n  trendRecsHtml += `\n    <div class=\"rec-item\">\n      <div class=\"rec-number\">${i + 1}</div>\n      <div class=\"rec-content\">\n        <h4>${rec.title}</h4>\n        <p>${rec.description}</p>\n        ${rec.impact ? `<span class=\"rec-impact\">${rec.impact}</span>` : ''}\n      </div>\n    </div>`;\n});\nreplace('{{TREND_RECOMMENDATIONS_HTML}}', trendRecsHtml || '<p class=\"empty-state\">No recommendations available</p>');\n\n// Generate filename\nconst fileName = `${categoryTitle.replace(/\\s+/g, '_')}_Dashboard_${dateFolderName}.html`;\n\nconsole.log('Dashboard built successfully!');\nconsole.log('File name:', fileName);\n\nreturn [{\n  json: {\n    html,\n    fileName,\n    categoryName,\n    dateFolderName\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2960,
        0
      ],
      "id": "95f59d8e-56a4-4836-86b7-e9a2a86b3496",
      "name": "Build Dashboard HTML"
    },
    {
      "parameters": {
        "jsCode": "// Prepare HTML for download as binary file\nconst { html, fileName } = $input.first().json;\n\nconst buffer = Buffer.from(html, 'utf8');\nconst binaryData = {\n  data: buffer.toString('base64'),\n  mimeType: 'text/html',\n  fileName: fileName\n};\n\nreturn [{\n  json: { fileName },\n  binary: { data: binaryData }\n}];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3168,
        0
      ],
      "id": "37610383-bf81-4f8c-9592-c5a3f5d2f986",
      "name": "Prepare Download"
    }
  ],
  "connections": {
    "Run Manually": {
      "main": [
        [
          {
            "node": "Find Wayfair Reports Folder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Find Wayfair Reports Folder": {
      "main": [
        [
          {
            "node": "List Root Contents",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "List Root Contents": {
      "main": [
        [
          {
            "node": "Identify Category & Template",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Identify Category & Template": {
      "main": [
        [
          {
            "node": "Download Template",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Template": {
      "main": [
        [
          {
            "node": "Store Template",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Store Template": {
      "main": [
        [
          {
            "node": "List Date Folders",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "List Date Folders": {
      "main": [
        [
          {
            "node": "Get Latest Date Only",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Latest Date Only": {
      "main": [
        [
          {
            "node": "List P2/P3 Files",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "List P2/P3 Files": {
      "main": [
        [
          {
            "node": "Identify P2 & P3 Files",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Identify P2 & P3 Files": {
      "main": [
        [
          {
            "node": "Download P2",
            "type": "main",
            "index": 0
          },
          {
            "node": "Download P3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download P2": {
      "main": [
        [
          {
            "node": "Rename P2 Binary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download P3": {
      "main": [
        [
          {
            "node": "Rename P3 Binary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Rename P2 Binary": {
      "main": [
        [
          {
            "node": "Merge P2 & P3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Rename P3 Binary": {
      "main": [
        [
          {
            "node": "Merge P2 & P3",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Merge P2 & P3": {
      "main": [
        [
          {
            "node": "Parse P2 & P3 Reports",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse P2 & P3 Reports": {
      "main": [
        [
          {
            "node": "Build Dashboard HTML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Dashboard HTML": {
      "main": [
        [
          {
            "node": "Prepare Download",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate"
  },
  "versionId": "5cce026d-2c40-4abc-9af4-eb4122aebd5f",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "id": "PlD984qyDOtIYHhZ",
  "tags": []
}