{
  "schemaVersion": "1.0.0",
  "workflow": {
    "id": "faceless-youtube-network",
    "name": "Faceless YouTube Channel Network",
    "description": "A reusable graph for researching, producing, reviewing, publishing, and improving long-form videos and their Shorts across any number of configured channels.",
    "status": "operational-core-provider-gated",
    "entryNode": "schedule",
    "successNode": "analytics",
    "sourceOfTruth": "youtube-automation-workflow.json"
  },
  "runtimeStatus": {
    "lastReviewed": "2026-07-27",
    "deployedVersion": 48,
    "operational": [
      "Omnicon product identity with a white production wordmark, app mark, favicon, and social preview",
      "public animated product landing page with reduced-motion support and a protected command center entry",
      "authenticated channel workspaces",
      "truthful 28-day portfolio performance with analytics and verified Studio revenue coverage plus freshness",
      "owner-scoped portfolio operations health with approval SLA, automation, publishing, production, billing, planning, and setup exceptions",
      "monthly client delivery capacity with committed, in-production, review, scheduled, published, blocked, remaining, and overbooked plan measurements",
      "persistent narrator, visual, music, and Shorts production briefs",
      "zero-input niche discovery with twenty ranked micro-niches, confidence labels, scoring assumptions, and a 52-title winner width test",
      "five-niche comparison with evidence-informed RPM ranges, competition, repeatability, audience, monetization, and risk analysis",
      "source-linked research and script jobs",
      "scheduled editorial autopilot with automatic topic, research, and script handoffs",
      "durable production state and approval gates",
      "asynchronous renderer submission and verified private output ingestion",
      "Shorts Factory lineage that promotes three verified vertical cuts into independent review and publishing items",
      "approval-triggered private YouTube upload queue with durable idempotency and audit provenance",
      "capacity-aware multi-tenant runner sweep contract",
      "private GitHub Actions scheduler with five-minute sweeps, protected Sites dispatch, repository-scoped secrets, serialized execution, and authenticated production heartbeat evidence",
      "private media storage",
      "client accounts and approval records",
      "authenticated tenant-scoped client review portal",
      "operator-managed client reviewer and viewer rosters",
      "hashed expiring client invitation links with role and email enforcement",
      "encrypted provider-neutral invitation delivery through Resend, Postmark, or SendGrid with configured-sender controls",
      "bounded invitation retries with atomic delivery claims, safe provider error codes, and automatic deletion of delivered or cancelled retry tokens",
      "provider-neutral monthly invoice ledger and client billing history",
      "YouTube OAuth, resumable video upload, custom thumbnails, scheduling, and analytics",
      "operator-gated performance learning proposals that can inform later topic planning without changing channel policy",
      "verified YouTube Studio revenue CSV imports",
      "owner-scoped workspace policies and retry limits",
      "atomic monthly AI spend reservations with per-request ceilings and reported-usage reconciliation",
      "encrypted owner-scoped bring-your-own-AI connections with dynamic model discovery, provider capability labels, a workspace fallback, and dedicated research and script routes",
      "multi-agent production routing that can use OpenAI for research, Kimi or another connected model for scripts, and ElevenLabs for narration while separate channel jobs run within the saved concurrency ceiling",
      "encrypted owner-scoped ElevenLabs connections with live voice, speech-model, and usage synchronization plus idempotent private narration generation",
      "streaming owner-scoped workspace archives with explicit credential and private-storage exclusions",
      "confirmed owner-scoped workspace reset across durable records, OAuth grants, and private media",
      "cursor-paginated owner-scoped activity ledger across production, automation, publishing, clients, billing, analytics, learning, AI, and channels",
      "truth-labeled client service economics with full-plan target-cost margin projections and attributable automation AI spend",
      "owner-scoped client operating cost ledger with production attribution, void-preserved audit history, and recorded margin-to-date controls",
      "historical client service-month profitability with frozen contract and cost snapshots, controlled reopen corrections, and append-only close events",
      "owner-scoped portfolio profitability reports that merge closed snapshots with truth-labeled live estimates and export formula-safe accounting CSVs",
      "owner-scoped production launch gate with credential, connection, and business-decision evidence plus a secret-free agent-readable JSON report"
    ],
    "providerGated": [
      "narration generation",
      "long-form video rendering",
      "Shorts extraction and rendering",
      "payment collection",
      "external client site access policy",
      "verified email sending domain and provider credential"
    ],
    "requiredProductionConfiguration": [
      "AI_PROVIDER_TOKEN_ENCRYPTION_KEY",
      "VOICE_PROVIDER_TOKEN_ENCRYPTION_KEY",
      "EMAIL_PROVIDER_TOKEN_ENCRYPTION_KEY",
      "CLIENT_PORTAL_EXTERNAL_ACCESS=1",
      "GOOGLE_CLIENT_ID",
      "GOOGLE_CLIENT_SECRET",
      "YOUTUBE_OAUTH_REDIRECT_URI",
      "YOUTUBE_TOKEN_ENCRYPTION_KEY",
      "AUTOMATION_RUNNER_SECRET",
      "AUTOMATION_SCHEDULER_PROVIDER=github_actions",
      "AUTOMATION_SCHEDULER_INTERVAL_MINUTES=5",
      "MEDIA_RENDERER_URL",
      "MEDIA_RENDERER_SECRET",
      "MEDIA_RENDERER_ALLOWED_DOWNLOAD_HOSTS"
    ],
    "environmentFallbacks": [
      "OPENAI_API_KEY"
    ],
    "monetaryAnalytics": "Do not infer. Use only owner-imported YouTube Studio exports; imported values retain estimated-revenue provenance."
  },
  "scaling": {
    "channelCount": 0,
    "strategy": "shared-orchestrator-with-isolated-channel-runs",
    "concurrencyLimit": 2,
    "rule": "Instantiate one run per due channel. Never mix artifacts, credentials, or learning data between channelId values.",
    "runKeyFormat": "{channelId}:{contentId}:{runId}"
  },
  "defaults": {
    "approvalMode": "manual-before-publish",
    "maxNodeAttempts": 3,
    "artifactRoot": "runs/{channelId}/{contentId}/{runId}",
    "timezone": "America/Los_Angeles",
    "longFormTargetMinutes": 10,
    "shortsPerVideo": 3
  },
  "nicheDiscovery": {
    "modes": [
      "discover",
      "compare"
    ],
    "discoverInputs": [
      "market",
      "language",
      "contentFormat",
      "priority",
      "budget",
      "cadence",
      "interests",
      "exclusions"
    ],
    "scoreWeights": {
      "demand": 25,
      "monetizationPotential": 20,
      "competitionGap": 20,
      "repeatability": 15,
      "productionFit": 10,
      "trendDurability": 10
    },
    "outputContract": {
      "rankedCandidates": 20,
      "testTitlesPerCandidate": 3,
      "winnerCalendarTitles": 52,
      "calendarPillars": 4
    },
    "truthRules": [
      "RPM is an evidence-informed estimate until owned-channel revenue data exists.",
      "Advertiser bid or CPC data is a monetization signal, not YouTube RPM.",
      "Competitor revenue must never be presented as private or directly observed.",
      "Every source link must use HTTPS and originate from the completed research."
    ],
    "handoffs": [
      "seed the five-niche comparison with a selected candidate and four ranked alternatives",
      "prefill a new channel workspace with the selected niche"
    ]
  },
  "channelConfigSchema": {
    "required": [
      "id",
      "name",
      "niche",
      "audience",
      "contentPillars",
      "uploadCadence",
      "scriptRequirements",
      "editorialAutopilot",
      "voice",
      "visualStyle",
      "publishing"
    ],
    "fields": {
      "id": "Stable machine-readable channel identifier.",
      "name": "Human-readable channel name.",
      "niche": "The subject area this channel owns.",
      "audience": "Who the content is for and what they want.",
      "contentPillars": "Allowed recurring topic categories.",
      "excludedTopics": "Topics, claims, or treatments the channel must avoid.",
      "uploadCadence": "Days, times, and frequency for long-form videos and Shorts.",
      "scriptRequirements": "Channel-specific hook, structure, tone, length, CTA, and sourcing rules.",
      "editorialAutopilot": "Whether topic planning is enabled, its interval, and the next scheduled planning time.",
      "voice": "Narrator identity, delivery style, pace, and pronunciation rules.",
      "visualStyle": "Editing, imagery, captions, colors, aspect ratios, and asset rules.",
      "publishing": "YouTube destination, privacy default, approval mode, and scheduling rules."
    }
  },
  "channels": [],
  "stateModel": {
    "run": {
      "required": [
        "runId",
        "channelId",
        "contentId",
        "currentNode",
        "status",
        "attempts",
        "artifacts",
        "decisions",
        "errors"
      ],
      "statusValues": [
        "queued",
        "running",
        "waiting",
        "needs-review",
        "failed",
        "completed"
      ]
    }
  },
  "stages": [
    {
      "id": "orchestration",
      "label": "Orchestration",
      "order": 1
    },
    {
      "id": "editorial",
      "label": "Editorial",
      "order": 2
    },
    {
      "id": "production",
      "label": "Production",
      "order": 3
    },
    {
      "id": "distribution",
      "label": "Distribution",
      "order": 4
    },
    {
      "id": "learning",
      "label": "Learning",
      "order": 5
    }
  ],
  "nodes": [
    {
      "id": "schedule",
      "label": "Schedule Trigger",
      "stage": "orchestration",
      "type": "trigger",
      "role": "orchestrator",
      "purpose": "Start work when a configured channel is due for a new long-form video.",
      "inputs": [
        "channel configs",
        "publishing calendar",
        "active-run registry"
      ],
      "outputs": [
        "due channel list"
      ],
      "writes": [
        "run.created"
      ]
    },
    {
      "id": "channel-router",
      "label": "Channel Router",
      "stage": "orchestration",
      "type": "router",
      "role": "orchestrator",
      "purpose": "Create an isolated run for each due channel and load its niche, rules, credentials reference, and history.",
      "inputs": [
        "due channel list",
        "channel config"
      ],
      "outputs": [
        "channel-scoped run context"
      ],
      "writes": [
        "run.context"
      ]
    },
    {
      "id": "topic-discovery",
      "label": "Topic Discovery",
      "stage": "editorial",
      "type": "agent",
      "role": "researcher",
      "purpose": "Find timely, searchable, channel-fit topic candidates without repeating recent coverage.",
      "inputs": [
        "channel niche",
        "content pillars",
        "recent video history",
        "trend and search sources"
      ],
      "outputs": [
        "topic-candidates.json"
      ],
      "qualityCriteria": [
        "Fits exactly one content pillar",
        "Has a clear audience promise",
        "Is not a duplicate of recent channel coverage",
        "Can be supported by credible sources"
      ]
    },
    {
      "id": "topic-gate",
      "label": "Topic Gate",
      "stage": "editorial",
      "type": "review",
      "role": "editor",
      "purpose": "Select or reject a topic using relevance, novelty, evidence, safety, and production feasibility.",
      "inputs": [
        "topic-candidates.json",
        "channel rules"
      ],
      "outputs": [
        "topic-decision.json"
      ],
      "decisionValues": [
        "pass",
        "retry",
        "hold"
      ],
      "retryTarget": "topic-discovery"
    },
    {
      "id": "research",
      "label": "Research Packet",
      "stage": "editorial",
      "type": "agent",
      "role": "researcher",
      "purpose": "Build a source-linked fact packet, story angle, counterpoints, and claims ledger for the approved topic.",
      "inputs": [
        "approved topic",
        "channel audience",
        "source policy",
        "research AI task route"
      ],
      "outputs": [
        "research-packet.md",
        "claims.json",
        "sources.json"
      ]
    },
    {
      "id": "research-qa",
      "label": "Evidence QA",
      "stage": "editorial",
      "type": "review",
      "role": "fact-checker",
      "purpose": "Check material claims against sources and flag uncertainty before a script is written.",
      "inputs": [
        "research-packet.md",
        "claims.json",
        "sources.json"
      ],
      "outputs": [
        "evidence-review.json"
      ],
      "decisionValues": [
        "pass",
        "retry",
        "hold"
      ],
      "retryTarget": "research"
    },
    {
      "id": "script",
      "label": "Script Writer",
      "stage": "editorial",
      "type": "agent",
      "role": "writer",
      "purpose": "Write an engaging, channel-specific script using only approved research and the configured script requirements.",
      "inputs": [
        "research-packet.md",
        "evidence-review.json",
        "script requirements",
        "script AI task route"
      ],
      "outputs": [
        "script.md",
        "script-claims.json"
      ]
    },
    {
      "id": "script-qa",
      "label": "Script Review",
      "stage": "editorial",
      "type": "review",
      "role": "independent reviewer",
      "purpose": "Review hook, retention, clarity, factual alignment, tone, originality, and policy risks.",
      "inputs": [
        "script.md",
        "script-claims.json",
        "channel rules"
      ],
      "outputs": [
        "script-review.json"
      ],
      "decisionValues": [
        "pass",
        "retry",
        "hold"
      ],
      "retryTarget": "script"
    },
    {
      "id": "narration",
      "label": "Narration",
      "stage": "production",
      "type": "agent",
      "role": "audio producer",
      "purpose": "Generate and privately store an ElevenLabs narration asset from the approved script using the workspace voice route.",
      "inputs": [
        "approved script",
        "voice profile",
        "encrypted ElevenLabs connection",
        "selected voice and speech model"
      ],
      "outputs": [
        "narration.mp3"
      ]
    },
    {
      "id": "visual-plan",
      "label": "Visual Plan + Assets",
      "stage": "production",
      "type": "agent",
      "role": "visual producer",
      "purpose": "Create a timestamped shot list and collect or generate rights-safe visual assets.",
      "inputs": [
        "approved script",
        "visual style",
        "asset policy"
      ],
      "outputs": [
        "shot-list.json",
        "asset-manifest.json",
        "assets/"
      ]
    },
    {
      "id": "metadata",
      "label": "Packaging",
      "stage": "production",
      "type": "agent",
      "role": "packaging editor",
      "purpose": "Draft title options, description, chapters, tags, thumbnail brief, and disclosure text.",
      "inputs": [
        "approved script",
        "topic decision",
        "channel style"
      ],
      "outputs": [
        "metadata.json",
        "thumbnail.png"
      ]
    },
    {
      "id": "assemble",
      "label": "Video Assembly",
      "stage": "production",
      "type": "tool",
      "role": "video renderer",
      "purpose": "Combine narration, visuals, captions, music, and channel branding into the long-form master.",
      "inputs": [
        "narration.mp3",
        "shot-list.json",
        "asset-manifest.json",
        "visual style"
      ],
      "outputs": [
        "long-form-master.mp4",
        "captions.srt",
        "render-report.json"
      ]
    },
    {
      "id": "video-qa",
      "label": "Video QA",
      "stage": "production",
      "type": "review",
      "role": "independent reviewer",
      "purpose": "Check audio, timing, captions, visual rights, brand fit, claims, and technical export quality.",
      "inputs": [
        "long-form-master.mp4",
        "captions.srt",
        "asset-manifest.json",
        "script-review.json"
      ],
      "outputs": [
        "video-review.json"
      ],
      "decisionValues": [
        "pass",
        "retry",
        "hold"
      ],
      "retryTarget": "assemble"
    },
    {
      "id": "shorts",
      "label": "Shorts Factory",
      "stage": "production",
      "type": "agent",
      "role": "short-form editor",
      "purpose": "Select strong standalone moments and re-edit them as vertical Shorts with new hooks and captions.",
      "inputs": [
        "approved long-form master",
        "approved script",
        "timings.json",
        "shorts settings"
      ],
      "outputs": [
        "shorts/",
        "shorts-manifest.json"
      ]
    },
    {
      "id": "shorts-qa",
      "label": "Shorts QA",
      "stage": "production",
      "type": "review",
      "role": "independent reviewer",
      "purpose": "Verify each Short is understandable alone, correctly framed, accurately captioned, and policy-safe.",
      "inputs": [
        "shorts/",
        "shorts-manifest.json"
      ],
      "outputs": [
        "shorts-review.json"
      ],
      "decisionValues": [
        "pass",
        "retry",
        "hold"
      ],
      "retryTarget": "shorts"
    },
    {
      "id": "approval",
      "label": "Publish Approval",
      "stage": "distribution",
      "type": "human-gate",
      "role": "channel owner",
      "purpose": "Approve the complete long-form and Shorts package. Channels in review-then-schedule mode may atomically queue a private upload only after this decision.",
      "inputs": [
        "video-review.json",
        "shorts-review.json",
        "metadata.json",
        "thumbnail.png"
      ],
      "outputs": [
        "publish-decision.json"
      ],
      "decisionValues": [
        "approve",
        "revise",
        "hold"
      ]
    },
    {
      "id": "publish-long",
      "label": "Publish Long-form",
      "stage": "distribution",
      "type": "tool",
      "role": "publisher",
      "purpose": "Upload the approved long-form video, captions, thumbnail, metadata, and schedule. Approval-triggered jobs begin private.",
      "inputs": [
        "approved publish package",
        "channel credential reference"
      ],
      "outputs": [
        "youtube-video-id",
        "publish-receipt.json"
      ]
    },
    {
      "id": "publish-shorts",
      "label": "Schedule Shorts",
      "stage": "distribution",
      "type": "tool",
      "role": "publisher",
      "purpose": "Upload and stagger approved Shorts, linking back to the related long-form video where appropriate.",
      "inputs": [
        "approved shorts package",
        "youtube-video-id",
        "channel credential reference"
      ],
      "outputs": [
        "short-video-ids",
        "shorts-publish-receipt.json"
      ]
    },
    {
      "id": "analytics",
      "label": "Analytics + Learning",
      "stage": "learning",
      "type": "agent",
      "role": "analyst",
      "purpose": "Collect performance at fixed intervals and turn results into bounded recommendations for future topics, scripts, packaging, and Shorts.",
      "inputs": [
        "published video ids",
        "channel benchmarks",
        "retention and reach metrics"
      ],
      "outputs": [
        "performance-snapshot.json",
        "learning-notes.md"
      ],
      "guardrail": "Recommendations may update a proposal queue but must not silently change channel policy, credentials, or factual standards."
    }
  ],
  "edges": [
    {
      "from": "schedule",
      "to": "channel-router",
      "kind": "success"
    },
    {
      "from": "channel-router",
      "to": "topic-discovery",
      "kind": "fan-out",
      "label": "one isolated run per due channel"
    },
    {
      "from": "topic-discovery",
      "to": "topic-gate",
      "kind": "success"
    },
    {
      "from": "topic-gate",
      "to": "research",
      "kind": "conditional",
      "condition": "decision == 'pass'"
    },
    {
      "from": "topic-gate",
      "to": "topic-discovery",
      "kind": "retry",
      "condition": "decision == 'retry'"
    },
    {
      "from": "research",
      "to": "research-qa",
      "kind": "success"
    },
    {
      "from": "research-qa",
      "to": "script",
      "kind": "conditional",
      "condition": "decision == 'pass'"
    },
    {
      "from": "research-qa",
      "to": "research",
      "kind": "retry",
      "condition": "decision == 'retry'"
    },
    {
      "from": "script",
      "to": "script-qa",
      "kind": "success"
    },
    {
      "from": "script-qa",
      "to": "narration",
      "kind": "fan-out",
      "condition": "decision == 'pass'"
    },
    {
      "from": "script-qa",
      "to": "visual-plan",
      "kind": "fan-out",
      "condition": "decision == 'pass'"
    },
    {
      "from": "script-qa",
      "to": "metadata",
      "kind": "fan-out",
      "condition": "decision == 'pass'"
    },
    {
      "from": "script-qa",
      "to": "script",
      "kind": "retry",
      "condition": "decision == 'retry'"
    },
    {
      "from": "narration",
      "to": "assemble",
      "kind": "fan-in"
    },
    {
      "from": "visual-plan",
      "to": "assemble",
      "kind": "fan-in"
    },
    {
      "from": "assemble",
      "to": "video-qa",
      "kind": "success"
    },
    {
      "from": "video-qa",
      "to": "shorts",
      "kind": "conditional",
      "condition": "decision == 'pass'"
    },
    {
      "from": "video-qa",
      "to": "assemble",
      "kind": "retry",
      "condition": "decision == 'retry'"
    },
    {
      "from": "shorts",
      "to": "shorts-qa",
      "kind": "success"
    },
    {
      "from": "shorts-qa",
      "to": "approval",
      "kind": "conditional",
      "condition": "decision == 'pass'"
    },
    {
      "from": "shorts-qa",
      "to": "shorts",
      "kind": "retry",
      "condition": "decision == 'retry'"
    },
    {
      "from": "metadata",
      "to": "approval",
      "kind": "fan-in"
    },
    {
      "from": "video-qa",
      "to": "approval",
      "kind": "fan-in",
      "condition": "decision == 'pass'"
    },
    {
      "from": "approval",
      "to": "publish-long",
      "kind": "conditional",
      "condition": "decision == 'approve'"
    },
    {
      "from": "publish-long",
      "to": "publish-shorts",
      "kind": "success"
    },
    {
      "from": "publish-shorts",
      "to": "analytics",
      "kind": "success"
    },
    {
      "from": "analytics",
      "to": "topic-discovery",
      "kind": "feedback",
      "label": "learning proposal for next run"
    }
  ],
  "retryPolicy": {
    "defaultMaxAttempts": 3,
    "onExhausted": "Set run status to needs-review and stop downstream nodes.",
    "rules": [
      "A retry must include structured reviewer feedback.",
      "A producer may not approve its own output.",
      "Do not reuse partial publish operations without idempotency checks.",
      "Hold decisions require a human-readable reason."
    ]
  },
  "globalGuardrails": [
    "Use only licensed, original, public-domain, or generated assets with recorded provenance.",
    "Keep source URLs and claim-to-source mappings for every material factual claim.",
    "Never publish with missing approval when approvalMode is manual-before-publish.",
    "Approval-triggered upload jobs must be private, idempotent, and backed by a ready item-scoped video plus an upload-authorized YouTube connection.",
    "Keep YouTube credentials outside artifacts and reference them by secret identifier only.",
    "Use idempotency keys for uploads so retries cannot create duplicate videos.",
    "Respect YouTube policies, disclosure requirements, copyright, privacy, and applicable law.",
    "Treat analytics as recommendations, not permission to drift outside the configured niche or safety rules.",
    "Only operator-accepted learning guidance may enter future planning prompts, where it remains bounded data rather than policy or instructions.",
    "Operational health queries must remain owner-scoped, derive from durable records, and never expose another workspace's incidents.",
    "Client delivery utilization counts only due-dated long-form work inside the selected service month and must surface plan overbooking instead of silently accepting excess commitments.",
    "Portfolio views must derive from synchronized Analytics rows; monetary totals and RPM must derive only from owner-imported Studio exports and expose missing coverage.",
    "Every interactive and automated OpenAI request must reserve budget before dispatch, enforce the workspace request ceiling, and reconcile the reservation to reported token and web-search usage."
  ],
  "artifacts": {
    "topic-candidates.json": "Ranked topic options with scores and evidence.",
    "research-packet.md": "Narrative research notes for the writer.",
    "claims.json": "Each factual claim mapped to one or more sources.",
    "script.md": "Approved narration script.",
    "narration.mp3": "Private ElevenLabs speech asset with owner, channel, production-item, voice, model, and idempotency provenance.",
    "timings.json": "Word, sentence, and segment timestamps.",
    "asset-manifest.json": "Asset path, source, license, and intended scene.",
    "metadata.json": "Titles, description, chapters, tags, disclosures, and thumbnail brief.",
    "video-review.json": "Technical, editorial, rights, and policy checks.",
    "shorts-manifest.json": "Short clip boundaries, hook, caption, CTA, and long-form relationship.",
    "publish-receipt.json": "Upload idempotency key, video id, privacy, and schedule.",
    "performance-snapshot.json": "Time-bounded analytics used by the learning node."
  },
  "implementationPhases": [
    {
      "id": "phase-1",
      "label": "Design + manual publishing",
      "status": "operational",
      "includes": [
        "channel configs",
        "topic through QA graph",
        "artifact contracts",
        "manual approval"
      ]
    },
    {
      "id": "phase-2",
      "label": "Automated production",
      "status": "provider-gated",
      "includes": [
        "voice",
        "assets",
        "assembly",
        "captions",
        "Shorts"
      ]
    },
    {
      "id": "phase-3",
      "label": "Publishing + analytics",
      "status": "operational-after-runtime-credentials",
      "includes": [
        "YouTube integration",
        "idempotent scheduling",
        "performance snapshots",
        "learning proposals"
      ]
    },
    {
      "id": "phase-4",
      "label": "Multi-channel scale",
      "status": "operational-core",
      "includes": [
        "concurrency controls",
        "cost limits",
        "per-channel isolation",
        "operations dashboard",
        "cross-channel exception ranking",
        "client plan utilization and overbooking controls",
        "portfolio analytics and revenue truth"
      ]
    }
  ]
}
