{"name":"Keyword goldmine workflow","nodes":[{"id":"a1b2c3d4-0001-4222-8333-444455556601","name":"Weekly Keyword Mining Run","type":"n8n-nodes-base.scheduleTrigger","typeVersion":1.2,"position":[-240,300],"parameters":{"rule":{"interval":[{"field":"days","daysInterval":7}]}}},{"id":"a1b2c3d4-0002-4222-8333-444455556602","name":"Pull GSC Search Terms","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[20,120],"parameters":{"method":"POST","url":"https://searchconsole.googleapis.com/webmasters/v3/sites/sc-domain%3Abrand.com/searchAnalytics/query","sendBody":true,"specifyBody":"json","jsonBody":"={{ JSON.stringify({ startDate: $now.minus({ days: 90 }).toFormat('yyyy-LL-dd'), endDate: $now.toFormat('yyyy-LL-dd'), dimensions: ['query'], rowLimit: 5000, dataState: 'final' }) }}","options":{}}},{"id":"a1b2c3d4-0003-4222-8333-444455556603","name":"Normalize GSC Terms","type":"n8n-nodes-base.code","typeVersion":2,"position":[280,120],"parameters":{"jsCode":"// Google Search Console: rows we ALREADY rank for = proven relevance, unproven upside.\n// Keep only queries with real impressions, and remember our current position + CTR.\nconst rows = $input.all().flatMap(i => i.json.rows || [i.json]);\n\nconst out = [];\nfor (const r of rows) {\n  const term = String((r.keys && r.keys[0]) || r.query || '').toLowerCase().trim();\n  if (!term || term.length < 3) continue;\n\n  const impressions = Number(r.impressions || 0);\n  const clicks      = Number(r.clicks || 0);\n  const position    = Number(r.position || 100);\n  const ctr         = impressions > 0 ? clicks / impressions : 0;\n\n  // Below 120 impressions in 90 days there is not enough signal to act on.\n  if (impressions < 120) continue;\n\n  out.push({\n    json: {\n      keyword: term,\n      source: 'gsc',\n      impressions,\n      clicks,\n      avg_position: Math.round(position * 10) / 10,\n      ctr: Math.round(ctr * 10000) / 10000,\n      // Striking distance = ranked 5-20: one push moves real traffic.\n      striking_distance: position > 4.5 && position <= 20,\n      competitor_domains: 0\n    }\n  });\n}\n\n// Highest-impression queries first so the merge keeps the strongest signal on dedupe.\nout.sort((a, b) => b.json.impressions - a.json.impressions);\nreturn out;"}},{"id":"a1b2c3d4-0004-4222-8333-444455556604","name":"Pull Competitor Keywords","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[20,480],"parameters":{"method":"POST","url":"https://api.dataforseo.com/v3/dataforseo_labs/google/competitors_domain/live","sendBody":true,"specifyBody":"json","jsonBody":"={{ JSON.stringify([{ target: 'competitor.com', location_code: 2840, language_code: 'en', limit: 1000, filters: [['keyword_data.keyword_info.search_volume', '>', 40]] }]) }}","options":{}}},{"id":"a1b2c3d4-0005-4222-8333-444455556605","name":"Normalize Competitor Terms","type":"n8n-nodes-base.code","typeVersion":2,"position":[280,480],"parameters":{"jsCode":"// Competitor keyword export (DataForSEO Labs style): terms rivals rank for and we do not.\nconst rows = $input.all().flatMap(i => (i.json.tasks?.[0]?.result?.[0]?.items) || i.json.items || [i.json]);\n\nconst seen = new Map();\nfor (const r of rows) {\n  const kd   = r.keyword_data || r;\n  const term = String(kd.keyword || '').toLowerCase().trim();\n  if (!term || term.length < 3) continue;\n\n  const info   = kd.keyword_info || {};\n  const props  = kd.keyword_properties || {};\n  const volume = Number(info.search_volume || 0);\n  if (volume < 40) continue;\n\n  const prev = seen.get(term);\n  const rec = {\n    keyword: term,\n    source: 'competitor',\n    search_volume: volume,\n    cpc: Number(info.cpc || 0),\n    competition: Number(info.competition || 0),            // 0-1 paid competition\n    keyword_difficulty: Number(props.keyword_difficulty || 50), // 0-100 organic KD\n    competitor_domains: prev ? prev.competitor_domains + 1 : 1,\n    competitor_best_rank: Math.min(Number(r.ranked_serp_element?.serp_item?.rank_group || 100), prev?.competitor_best_rank ?? 100)\n  };\n  seen.set(term, rec);\n}\n\nreturn [...seen.values()].map(r => ({ json: r }));"}},{"id":"a1b2c3d4-0006-4222-8333-444455556606","name":"Pool Both Keyword Sources","type":"n8n-nodes-base.merge","typeVersion":3,"position":[540,300],"parameters":{"mode":"append","options":{}}},{"id":"a1b2c3d4-0007-4222-8333-444455556607","name":"Dedupe & Score Goldmine","type":"n8n-nodes-base.code","typeVersion":2,"position":[800,300],"parameters":{"jsCode":"// ── KEYWORD GOLDMINE SCORING ──────────────────────────────────────────────\n// Blend the two pools, dedupe on the normalised keyword, then score every term on:\n//   1. opportunity  = volume vs. how hard it is to win  (volume-to-competition)\n//   2. intent       = how close the phrasing is to a purchase\n//   3. proximity    = how close we already are to page one\n// goldmine_score = 0-100. Anything >= 70 goes straight into the content queue.\n\nconst items = $input.all().map(i => i.json);\n\nconst norm = k => String(k || '')\n  .toLowerCase()\n  .replace(/[^a-z0-9 ]/g, ' ')\n  .replace(/\\b(the|a|an|for|of|to|in|my|your)\\b/g, ' ')\n  .replace(/\\s+/g, ' ')\n  .trim();\n\n// ---- dedupe: merge GSC row + competitor row for the same normalised term ----\nconst merged = new Map();\nfor (const r of items) {\n  const key = norm(r.keyword);\n  if (!key) continue;\n  const cur = merged.get(key) || { keyword: r.keyword, norm_key: key, sources: [] };\n  merged.set(key, {\n    ...cur,\n    keyword: (cur.keyword || '').length >= (r.keyword || '').length ? cur.keyword : r.keyword,\n    sources: [...new Set([...cur.sources, r.source])],\n    impressions:         Math.max(cur.impressions || 0, r.impressions || 0),\n    clicks:              Math.max(cur.clicks || 0, r.clicks || 0),\n    ctr:                 Math.max(cur.ctr || 0, r.ctr || 0),\n    avg_position:        Math.min(cur.avg_position ?? 100, r.avg_position ?? 100),\n    search_volume:       Math.max(cur.search_volume || 0, r.search_volume || 0),\n    cpc:                 Math.max(cur.cpc || 0, r.cpc || 0),\n    competition:         Math.max(cur.competition || 0, r.competition || 0),\n    keyword_difficulty:  Math.max(cur.keyword_difficulty || 0, r.keyword_difficulty || 0),\n    competitor_domains:  Math.max(cur.competitor_domains || 0, r.competitor_domains || 0),\n    competitor_best_rank: Math.min(cur.competitor_best_rank ?? 100, r.competitor_best_rank ?? 100)\n  });\n}\n\n// ---- commercial intent lexicon ----\nconst INTENT = [\n  { re: /\\b(buy|order|price|pricing|cost|cheap|discount|coupon|deal|for sale|shipping)\\b/, w: 32, label: 'transactional' },\n  { re: /\\b(best|top|review|reviews|vs|versus|alternative|alternatives|comparison)\\b/,      w: 24, label: 'commercial' },\n  { re: /\\b(software|tool|tools|service|agency|platform|app|subscription)\\b/,              w: 14, label: 'commercial' },\n  { re: /\\b(near me|online|store|shop)\\b/,                                                 w: 12, label: 'local' },\n  { re: /\\b(how|what|why|guide|tutorial|examples|template|checklist)\\b/,                  w: 4,  label: 'informational' },\n  { re: /\\b(free|meaning|definition|jobs|salary|reddit|download)\\b/,                      w: -12, label: 'junk' }\n];\n\nconst clamp = (n, lo, hi) => Math.min(hi, Math.max(lo, n));\nconst out = [];\n\nfor (const r of merged.values()) {\n  // Fall back to impressions as a volume proxy when only GSC knows the term.\n  const volume = r.search_volume || Math.round((r.impressions || 0) * 1.35);\n  if (volume < 40) continue;\n\n  // 1. OPPORTUNITY — volume relative to the effort needed to rank.\n  // difficulty floor of 8 keeps the ratio from exploding on zero-KD terms.\n  const difficulty = clamp(r.keyword_difficulty || (r.competition * 100) || 45, 8, 100);\n  const ratio      = volume / difficulty;                  // searches per difficulty point\n  const opportunity = clamp((Math.log10(ratio + 1) / Math.log10(120)) * 100, 0, 100);\n\n  // 2. INTENT — lexicon hits plus CPC (advertisers only bid on money terms).\n  let intentPts = 0;\n  const labels = [];\n  for (const s of INTENT) {\n    if (s.re.test(' ' + r.norm_key + ' ')) { intentPts += s.w; labels.push(s.label); }\n  }\n  const cpcPts = clamp((r.cpc || 0) * 8, 0, 26);           // $3.25 CPC ≈ full marks\n  const intent = clamp(40 + intentPts + cpcPts, 0, 100);\n  const intent_type = labels.includes('transactional') ? 'transactional'\n    : labels.includes('commercial') ? 'commercial'\n    : labels.includes('local') ? 'local'\n    : labels.includes('informational') ? 'informational' : 'unclassified';\n\n  // 3. PROXIMITY — how much lift is already banked.\n  const pos = r.avg_position ?? 100;\n  const proximity = pos >= 100 ? 20              // brand new term, no ranking yet\n    : pos <= 3   ? 25                            // already winning, little upside\n    : pos <= 10  ? 100                           // page one edge — cheapest wins\n    : pos <= 20  ? 78\n    : pos <= 40  ? 45 : 28;\n\n  // Validation bonus: several competitors ranking = the term converts for somebody.\n  const validation = clamp((r.competitor_domains || 0) * 6, 0, 18);\n\n  const goldmine_score = Math.round(\n    clamp(opportunity * 0.40 + intent * 0.35 + proximity * 0.25 + validation, 0, 100)\n  );\n\n  // Traffic we'd realistically capture at the target position (CTR curve by rank).\n  const CTR_CURVE = { 1: 0.284, 2: 0.152, 3: 0.099, 4: 0.071, 5: 0.052, 6: 0.041, 7: 0.033, 8: 0.028, 9: 0.024, 10: 0.021 };\n  const target_position = pos <= 10 ? Math.max(1, Math.floor(pos) - 2) : goldmine_score >= 70 ? 5 : 8;\n  const target_ctr = CTR_CURVE[clamp(target_position, 1, 10)] || 0.02;\n  const current_clicks = Math.round(volume * (r.ctr || (pos <= 10 ? (CTR_CURVE[Math.round(pos)] || 0.02) : 0)));\n  const projected_clicks = Math.round(volume * target_ctr);\n  const incremental_clicks = Math.max(0, projected_clicks - current_clicks);\n  const projected_value = Math.round(incremental_clicks * (r.cpc || 1.2) * 100) / 100;\n\n  // Rough pacing: 4 briefs shipped per week, ~6 weeks from brief to ranking.\n  out.push({\n    keyword: r.keyword,\n    sources: r.sources.join('+'),\n    search_volume: volume,\n    cpc: Math.round((r.cpc || 0) * 100) / 100,\n    keyword_difficulty: Math.round(difficulty),\n    competitor_domains: r.competitor_domains || 0,\n    avg_position: pos >= 100 ? null : r.avg_position,\n    opportunity_score: Math.round(opportunity),\n    intent_score: Math.round(intent),\n    intent_type,\n    proximity_score: proximity,\n    goldmine_score,\n    target_position,\n    current_clicks,\n    projected_clicks,\n    incremental_clicks,\n    projected_monthly_value: projected_value,\n    tier: goldmine_score >= 70 ? 'goldmine' : goldmine_score >= 45 ? 'watchlist' : 'reject'\n  });\n}\n\n// Rank, then attach a publishing plan: 4 briefs a week, 6 weeks to rank.\nout.sort((a, b) => b.goldmine_score - a.goldmine_score || b.projected_monthly_value - a.projected_monthly_value);\n\nconst PER_WEEK = 4;\nreturn out.map((r, idx) => {\n  const week = Math.floor(idx / PER_WEEK) + 1;\n  const d = new Date();\n  d.setDate(d.getDate() + week * 7);\n  return { json: { ...r, rank: idx + 1, brief_week: week, brief_due: d.toISOString().slice(0, 10), ranking_eta_weeks: week + 6 } };\n});"}},{"id":"a1b2c3d4-0008-4222-8333-444455556608","name":"Drop Dust Volume Terms","type":"n8n-nodes-base.filter","typeVersion":2,"position":[1060,300],"parameters":{"conditions":{"options":{"caseSensitive":true,"version":2},"combinator":"and","conditions":[{"id":"f1","leftValue":"={{ $json.search_volume }}","rightValue":80,"operator":{"type":"number","operation":"gte"}},{"id":"f2","leftValue":"={{ $json.intent_score }}","rightValue":35,"operator":{"type":"number","operation":"gte"}}]},"options":{}}},{"id":"a1b2c3d4-0009-4222-8333-444455556609","name":"Goldmine Score 70+?","type":"n8n-nodes-base.if","typeVersion":2,"position":[1320,300],"parameters":{"conditions":{"options":{"caseSensitive":true,"version":2},"combinator":"and","conditions":[{"id":"g1","leftValue":"={{ $json.goldmine_score }}","rightValue":70,"operator":{"type":"number","operation":"gte"}},{"id":"g2","leftValue":"={{ $json.incremental_clicks }}","rightValue":25,"operator":{"type":"number","operation":"gte"}}]},"options":{}}},{"id":"a1b2c3d4-0010-4222-8333-444455556610","name":"Build Content Brief Row","type":"n8n-nodes-base.set","typeVersion":3.3,"position":[1580,120],"parameters":{"assignments":{"assignments":[{"id":"s1","name":"keyword","value":"={{ $json.keyword }}","type":"string"},{"id":"s2","name":"goldmine_score","value":"={{ $json.goldmine_score }}","type":"number"},{"id":"s3","name":"search_volume","value":"={{ $json.search_volume }}","type":"number"},{"id":"s4","name":"keyword_difficulty","value":"={{ $json.keyword_difficulty }}","type":"number"},{"id":"s5","name":"intent_type","value":"={{ $json.intent_type }}","type":"string"},{"id":"s6","name":"incremental_clicks","value":"={{ $json.incremental_clicks }}","type":"number"},{"id":"s7","name":"projected_monthly_value","value":"={{ $json.projected_monthly_value }}","type":"number"},{"id":"s8","name":"brief_due","value":"={{ $json.brief_due }}","type":"string"},{"id":"s9","name":"ranking_eta_weeks","value":"={{ $json.ranking_eta_weeks }}","type":"number"}]},"options":{}}},{"id":"a1b2c3d4-0011-4222-8333-444455556611","name":"Draft Angle & Title","type":"@n8n/n8n-nodes-langchain.openAi","typeVersion":1.8,"position":[1840,120],"parameters":{"modelId":{"__rl":true,"value":"gpt-4o-mini","mode":"list"},"messages":{"values":[{"role":"system","content":"You are an SEO content strategist. Reply with one H1 title (max 62 chars) and one sentence on the angle that beats the current page-one results. No preamble."},{"content":"=Keyword: {{ $json.keyword }}\nIntent: {{ $json.intent_type }}\nMonthly volume: {{ $json.search_volume }}\nDifficulty: {{ $json.keyword_difficulty }}"}]},"options":{}}},{"id":"a1b2c3d4-0021-4222-8333-444455556621","name":"Attach Angle To Brief","type":"n8n-nodes-base.code","typeVersion":2,"position":[2100,-20],"parameters":{"jsCode":"// The LLM node replaces the item payload with its own message object, so the\n// brief fields built upstream would never reach the sheet or Slack. Stitch the\n// generated angle back onto the matching brief row, item by item.\nreturn $input.all().map((item, idx) => {\n  const brief = $('Build Content Brief Row').all()[idx].json;\n  const raw = item.json.message?.content ?? item.json.text ?? item.json.content ?? '';\n  const lines = String(raw).split('\\n').map(l => l.trim()).filter(Boolean);\n\n  return {\n    json: {\n      ...brief,\n      suggested_title: (lines[0] || '').replace(/^#+\\s*/, '').replace(/^[\"']|[\"']$/g, ''),\n      content_angle: lines.slice(1).join(' ') || lines[0] || '',\n      drafted_at: new Date().toISOString()\n    }\n  };\n});"}},{"id":"a1b2c3d4-0012-4222-8333-444455556612","name":"File Goldmine Keywords","type":"n8n-nodes-base.googleSheets","typeVersion":4.5,"position":[2100,120],"parameters":{"operation":"append","documentId":{"__rl":true,"value":"SHEET_ID","mode":"id"},"sheetName":{"__rl":true,"value":"gid=0","mode":"list","cachedResultName":"Goldmine"},"columns":{"mappingMode":"autoMapInputData","value":{},"matchingColumns":[]},"options":{}}},{"id":"a1b2c3d4-0013-4222-8333-444455556613","name":"Ping Content Team","type":"n8n-nodes-base.slack","typeVersion":2.2,"position":[2360,120],"parameters":{"select":"channel","channelId":{"__rl":true,"value":"#seo-content","mode":"name"},"text":"=⛏️ Goldmine keyword: *{{ $json.keyword }}* — score {{ $json.goldmine_score }}, {{ $json.search_volume }}/mo, KD {{ $json.keyword_difficulty }}, {{ $json.intent_type }} intent. +{{ $json.incremental_clicks }} clicks/mo (~${{ $json.projected_monthly_value }}). Brief due {{ $json.brief_due }}.","otherOptions":{}}},{"id":"a1b2c3d4-0014-4222-8333-444455556614","name":"Watchlist Score 45+?","type":"n8n-nodes-base.if","typeVersion":2,"position":[1580,500],"parameters":{"conditions":{"options":{"caseSensitive":true,"version":2},"combinator":"and","conditions":[{"id":"w1","leftValue":"={{ $json.goldmine_score }}","rightValue":45,"operator":{"type":"number","operation":"gte"}}]},"options":{}}},{"id":"a1b2c3d4-0015-4222-8333-444455556615","name":"File Watchlist Keywords","type":"n8n-nodes-base.googleSheets","typeVersion":4.5,"position":[1840,400],"parameters":{"operation":"append","documentId":{"__rl":true,"value":"SHEET_ID","mode":"id"},"sheetName":{"__rl":true,"value":"gid=1","mode":"list","cachedResultName":"Watchlist"},"columns":{"mappingMode":"autoMapInputData","value":{},"matchingColumns":[]},"options":{}}},{"id":"a1b2c3d4-0016-4222-8333-444455556616","name":"Diagnose Rejected Terms","type":"n8n-nodes-base.code","typeVersion":2,"position":[1840,640],"parameters":{"jsCode":"// Rejects are still information: tell us WHY the pool is thin so the next\n// competitor seed list can be adjusted instead of blindly re-run.\nconst rows = $input.all().map(i => i.json);\n\nconst reasons = { low_volume: 0, too_hard: 0, weak_intent: 0, no_proximity: 0 };\nfor (const r of rows) {\n  if (r.search_volume < 150) reasons.low_volume++;\n  else if (r.keyword_difficulty >= 65) reasons.too_hard++;\n  else if (r.intent_score < 45) reasons.weak_intent++;\n  else reasons.no_proximity++;\n}\n\nconst dominant = Object.entries(reasons).sort((a, b) => b[1] - a[1])[0] || ['none', 0];\n\nreturn [{\n  json: {\n    logged_at: new Date().toISOString(),\n    rejected_terms: rows.length,\n    avg_score: rows.length ? Math.round(rows.reduce((s, r) => s + r.goldmine_score, 0) / rows.length) : 0,\n    reason_low_volume: reasons.low_volume,\n    reason_too_hard: reasons.too_hard,\n    reason_weak_intent: reasons.weak_intent,\n    reason_no_proximity: reasons.no_proximity,\n    dominant_reason: dominant[0],\n    sample_terms: rows.slice(0, 15).map(r => r.keyword).join(', '),\n    next_action: dominant[0] === 'too_hard'\n      ? 'Seed the competitor list with smaller/newer domains — current rivals are too authoritative.'\n      : dominant[0] === 'low_volume'\n      ? 'Widen the seed set: current queries are long-tail dust.'\n      : 'Add transactional modifiers (buy/price/best/vs) to the competitor seed queries.'\n  }\n}];"}},{"id":"a1b2c3d4-0017-4222-8333-444455556617","name":"Log Mining Diagnostics","type":"n8n-nodes-base.googleSheets","typeVersion":4.5,"position":[2100,640],"parameters":{"operation":"append","documentId":{"__rl":true,"value":"SHEET_ID","mode":"id"},"sheetName":{"__rl":true,"value":"gid=2","mode":"list","cachedResultName":"Run log"},"columns":{"mappingMode":"autoMapInputData","value":{},"matchingColumns":[]},"options":{}}},{"id":"a1b2c3d4-0018-4222-8333-444455556618","name":"Sticky Sources","type":"n8n-nodes-base.stickyNote","typeVersion":1,"position":[-40,-180],"parameters":{"content":"## 1. MINE\nTwo pools every Monday:\n- GSC queries we already get impressions for (proven relevance, position 5-20 = striking distance)\n- Competitor keywords from DataForSEO Labs (proven demand we do not touch)\nEach normalizer throws away dust (<120 impressions / <40 volume).","height":300,"width":460,"color":4}},{"id":"a1b2c3d4-0019-4222-8333-444455556619","name":"Sticky Scoring","type":"n8n-nodes-base.stickyNote","typeVersion":1,"position":[760,-180],"parameters":{"content":"## 2. SCORE\ngoldmine_score = 0.40 x opportunity (log volume-to-difficulty)\n+ 0.35 x commercial intent (lexicon + CPC)\n+ 0.25 x proximity (current SERP position)\n+ competitor validation bonus.\nDedupe merges the GSC row and competitor row for the same normalised term.","height":300,"width":460,"color":5}},{"id":"a1b2c3d4-0020-4222-8333-444455556620","name":"Sticky Filing","type":"n8n-nodes-base.stickyNote","typeVersion":1,"position":[1560,-180],"parameters":{"content":"## 3. FILE\n70+ and >=25 incremental clicks -> brief row + AI angle + Goldmine sheet + Slack.\n45-69 -> Watchlist sheet, re-scored next week.\n<45 -> diagnosed in bulk so the seed list gets fixed, not blindly re-run.","height":300,"width":460,"color":3}}],"connections":{"Weekly Keyword Mining Run":{"main":[[{"node":"Pull GSC Search Terms","type":"main","index":0},{"node":"Pull Competitor Keywords","type":"main","index":0}]]},"Pull GSC Search Terms":{"main":[[{"node":"Normalize GSC Terms","type":"main","index":0}]]},"Normalize GSC Terms":{"main":[[{"node":"Pool Both Keyword Sources","type":"main","index":0}]]},"Pull Competitor Keywords":{"main":[[{"node":"Normalize Competitor Terms","type":"main","index":0}]]},"Normalize Competitor Terms":{"main":[[{"node":"Pool Both Keyword Sources","type":"main","index":1}]]},"Pool Both Keyword Sources":{"main":[[{"node":"Dedupe & Score Goldmine","type":"main","index":0}]]},"Dedupe & Score Goldmine":{"main":[[{"node":"Drop Dust Volume Terms","type":"main","index":0}]]},"Drop Dust Volume Terms":{"main":[[{"node":"Goldmine Score 70+?","type":"main","index":0}]]},"Goldmine Score 70+?":{"main":[[{"node":"Build Content Brief Row","type":"main","index":0}],[{"node":"Watchlist Score 45+?","type":"main","index":0}]]},"Build Content Brief Row":{"main":[[{"node":"Draft Angle & Title","type":"main","index":0}]]},"Draft Angle & Title":{"main":[[{"node":"Attach Angle To Brief","type":"main","index":0}]]},"Attach Angle To Brief":{"main":[[{"node":"File Goldmine Keywords","type":"main","index":0}]]},"File Goldmine Keywords":{"main":[[{"node":"Ping Content Team","type":"main","index":0}]]},"Watchlist Score 45+?":{"main":[[{"node":"File Watchlist Keywords","type":"main","index":0}],[{"node":"Diagnose Rejected Terms","type":"main","index":0}]]},"Diagnose Rejected Terms":{"main":[[{"node":"Log Mining Diagnostics","type":"main","index":0}]]}},"settings":{"executionOrder":"v1"},"pinData":{}}