// TASKS PLATFORM — Pub/sub store (TaskStore) + extended enterprise data.
// Wraps TASKS seed with mutable clone, lifecycle events, cross-platform bridge, and a React hook.
(function () {
  if (!window.TASKS) { console.warn('TasksStore: TASKS not loaded'); return; }

  // ── Pub/sub bus ─────────────────────────────────────────────────────────
  const TkBus = {
    _subs: {},
    on(topic, fn) {
      (this._subs[topic] = this._subs[topic] || []).push(fn);
      return () => { this._subs[topic] = (this._subs[topic] || []).filter(f => f !== fn); };
    },
    emit(topic, data) {
      (this._subs[topic] || []).slice().forEach(fn => { try { fn(data); } catch (e) { console.error(e); } });
      (this._subs['*']   || []).slice().forEach(fn => { try { fn(topic, data); } catch (e) { console.error(e); } });
      try { window.dispatchEvent(new CustomEvent('arbiter:task.' + topic, { detail: data })); } catch (e) {}
    },
  };

  const todayISO = () => new Date().toISOString().slice(0, 10);
  const nowStamp = () => new Date().toISOString().slice(0, 16).replace('T', ' ');
  const uid = (p) => `${p}-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;

  // ── Mutable clone of seed data ──────────────────────────────────────────
  const tasks = JSON.parse(JSON.stringify(window.TASKS));

  // Promote blockedBy string to array + add blocks[] back-index
  tasks.forEach(t => {
    if (!Array.isArray(t.blockedBy)) t.blockedBy = t.blockedBy ? [t.blockedBy] : [];
    t.blocks = [];
    t.comments = [];
    t.watchers = [];
    t.timeEntries = [];
    t.billable = t.category !== 'Admin';
    t.recurrence = null; // { cadence:'weekly', nextDue, interval }
    t.slaHours = null;
  });
  tasks.forEach(t => {
    t.blockedBy.forEach(bid => {
      const src = tasks.find(x => x.id === bid);
      if (src && !src.blocks.includes(t.id)) src.blocks.push(t.id);
    });
  });

  // Saved filter views
  const savedViews = [
    { id: 'TV-1', name: 'My Overdue',          filter: { assignee: 'M. Kirkland', overdue: true }, system: true },
    { id: 'TV-2', name: 'High Priority / Week',filter: { priority: 'high', thisWeek: true },      system: true },
    { id: 'TV-3', name: 'Awaiting Review',     filter: { status: 'In Review' },                   system: true },
    { id: 'TV-4', name: 'Blocked Tasks',       filter: { blocked: true },                         system: true },
  ];

  // Task templates (#7 Templates library)
  const templates = [
    {
      id: 'TPL-1', name: 'Motion Filing',      category: 'Filing',
      estimatedHours: 8,
      subtasks: ['Draft motion','Cite-check','Partner review','File with court','Serve opposing counsel'],
      description: 'Standard procedure for filing a motion.',
    },
    {
      id: 'TPL-2', name: 'Deposition Prep',    category: 'Deposition',
      estimatedHours: 10,
      subtasks: ['Compile exhibit list','Draft topic areas','Review prior testimony','Prep witness','Run-through'],
      description: 'Prepare deponent and outline for a deposition.',
    },
    {
      id: 'TPL-3', name: 'New Matter Intake',  category: 'Admin',
      estimatedHours: 3,
      subtasks: ['Conflicts check','Open matter in billing','Set up doc folder','Draft engagement letter','Client intake call'],
      description: 'Onboard a new matter end-to-end.',
    },
    {
      id: 'TPL-4', name: 'Document Review Batch', category: 'Review',
      estimatedHours: 12,
      subtasks: ['Load batch','First-pass relevance','Privilege review','QC sampling','Produce report'],
      description: 'FCPA / discovery doc review workflow.',
    },
    {
      id: 'TPL-5', name: 'Expert Designation', category: 'Filing',
      estimatedHours: 4,
      subtasks: ['Confirm availability','Finalize CV','Draft designation letter','Serve on counsel','File with court'],
      description: 'Designate and disclose an expert witness.',
    },
  ];

  // Audit log (seeded with creation rows)
  const auditLog = tasks.map(t => ({
    id: `AU-${t.id}`, taskId: t.id, action: 'Task Created', actor: t.assignee,
    ts: `${t.dueDate} 09:00`, detail: `${t.category} · ${t.title}`,
  }));

  // Category SLA history (for #15 analytics)
  const categorySla = (() => {
    const m = {};
    tasks.forEach(t => {
      if (!m[t.category]) m[t.category] = { count: 0, est: 0, logged: 0 };
      m[t.category].count++;
      m[t.category].est += t.estimatedHours;
      m[t.category].logged += t.loggedHours;
    });
    Object.values(m).forEach(v => {
      v.avgEst = Math.round((v.est / v.count) * 10) / 10;
      v.avgLogged = Math.round((v.logged / v.count) * 10) / 10;
      v.variance = v.avgEst ? Math.round(((v.avgLogged - v.avgEst) / v.avgEst) * 100) : 0;
    });
    return m;
  })();

  // Assignee weekly capacity (hrs/wk) — for #13 workload balancing
  const capacity = {
    'M. Kirkland': 40, 'S. Chen': 40, 'R. Vasquez': 40,
    'L. Torres': 40, 'A. Petrov': 35, 'J. Park': 40,
  };

  // Auto-assign rules (#11): matterId prefix → default assignee
  const autoAssignRules = [
    { match: /IP|Patent|Blackwell/i,     assignee: 'J. Park',     reason: 'IP / patent specialist' },
    { match: /Pharma|Compliance|FCPA/i,  assignee: 'S. Chen',     reason: 'Compliance lead' },
    { match: /Redstone|Meridian/i,       assignee: 'M. Kirkland', reason: 'Lead partner on matter' },
    { match: /Pacific|Shipping/i,        assignee: 'L. Torres',   reason: 'Antitrust team' },
    { match: /Thornton|Estate/i,         assignee: 'R. Vasquez',  reason: 'Estates lead' },
    { match: /Chen|Marshall|Greenfield/i,assignee: 'A. Petrov',   reason: 'Litigation generalist' },
  ];

  // Reminder lead times in hours for due-date notifications (#22)
  const reminderPolicy = { high: 48, medium: 24, low: 12 };

  // ── Store API ───────────────────────────────────────────────────────────
  const TaskStore = {
    data: {
      tasks,
      savedViews,
      templates,
      auditLog,
      categorySla,
      capacity,
      autoAssignRules,
      reminderPolicy,
      mentions: [],           // inbox of @mentions
      activeTimer: null,      // { taskId, startedAt }
    },
    bus: TkBus,

    _audit(taskId, action, detail, actor = 'J. Saadein') {
      this.data.auditLog.unshift({
        id: uid('AU'), taskId, action, actor, detail, ts: nowStamp(),
      });
    },

    _recomputeSla() {
      const m = {};
      this.data.tasks.forEach(t => {
        if (!m[t.category]) m[t.category] = { count: 0, est: 0, logged: 0 };
        m[t.category].count++;
        m[t.category].est += t.estimatedHours;
        m[t.category].logged += t.loggedHours;
      });
      Object.values(m).forEach(v => {
        v.avgEst = Math.round((v.est / v.count) * 10) / 10;
        v.avgLogged = Math.round((v.logged / v.count) * 10) / 10;
        v.variance = v.avgEst ? Math.round(((v.avgLogged - v.avgEst) / v.avgEst) * 100) : 0;
      });
      this.data.categorySla = m;
    },

    // Task CRUD -----------------------------------------------------------
    createTask({ title, matter = 'Unassigned', matterId = '', assignee, priority = 'medium', status = 'To Do',
                 dueDate = todayISO(), category = 'Admin', estimatedHours = 1, description = '',
                 subtasks = [], blockedBy = [], linkedDeadlines = [], linkedDocs = [], linkedEvidence = [],
                 recurrence = null }) {
      // Auto-assign if not provided
      if (!assignee) {
        const rule = this.data.autoAssignRules.find(r => r.match.test(matter + ' ' + matterId));
        assignee = rule ? rule.assignee : 'M. Kirkland';
      }
      const idx = this.data.tasks.length + 1;
      const id = `T-${String(idx).padStart(3, '0')}`;
      const task = {
        id, title, matter, matterId, assignee, priority, status,
        dueDate, category, estimatedHours, loggedHours: 0,
        description, blockedBy: Array.isArray(blockedBy) ? blockedBy : [blockedBy].filter(Boolean),
        linkedDeadlines, linkedDocs, linkedEvidence,
        subtasks: subtasks.map(t => typeof t === 'string' ? { t, done: false } : t),
        activity: [{ user: assignee, action: 'Created task', time: 'just now' }],
        blocks: [], comments: [], watchers: [], timeEntries: [],
        billable: category !== 'Admin', recurrence, slaHours: null,
      };
      this.data.tasks.push(task);
      // Reverse-index blocks
      task.blockedBy.forEach(bid => {
        const src = this.data.tasks.find(x => x.id === bid);
        if (src && !src.blocks.includes(task.id)) src.blocks.push(task.id);
      });
      this._audit(id, 'Task Created', `${category} · ${title}`, assignee);
      this._recomputeSla();
      TkBus.emit('created', { task });
      return task;
    },

    updateTask(id, patch) {
      const t = this.data.tasks.find(x => x.id === id);
      if (!t) return null;
      const prev = { ...t };
      Object.assign(t, patch);
      this._audit(id, 'Task Updated', `Fields: ${Object.keys(patch).join(', ')}`);
      if (patch.status && patch.status !== prev.status) {
        if (patch.status === 'Done') TkBus.emit('completed', { task: t });
        if (prev.status === 'Done' && patch.status !== 'Done') TkBus.emit('reopened', { task: t });
      }
      TkBus.emit('updated', { task: t });
      return t;
    },

    setStatus(id, status) { return this.updateTask(id, { status }); },

    toggleSubtask(taskId, idx) {
      const t = this.data.tasks.find(x => x.id === taskId);
      if (!t) return null;
      const s = t.subtasks[idx];
      if (!s) return null;
      s.done = !s.done;
      const doneCount = t.subtasks.filter(x => x.done).length;
      this._audit(taskId, 'Subtask Toggled', `${s.t} → ${s.done ? 'done' : 'open'} (${doneCount}/${t.subtasks.length})`);
      TkBus.emit('subtask.toggled', { task: t, subtask: s });
      // If all subtasks complete and status !== Done, flag ready for review
      if (doneCount === t.subtasks.length && t.subtasks.length && t.status === 'In Progress') {
        t.status = 'In Review';
        TkBus.emit('updated', { task: t });
      }
      return t;
    },

    completeTask(id) {
      const t = this.data.tasks.find(x => x.id === id);
      if (!t) return null;
      t.status = 'Done';
      t.loggedHours = Math.max(t.loggedHours, t.estimatedHours * 0.9);
      this._audit(id, 'Task Completed', `${t.title}`);
      TkBus.emit('completed', { task: t });
      // Spawn next recurrence instance
      if (t.recurrence) {
        const next = new Date(t.dueDate);
        const step = t.recurrence.cadence === 'daily' ? 1
                   : t.recurrence.cadence === 'weekly' ? 7
                   : t.recurrence.cadence === 'monthly' ? 30 : 7;
        next.setDate(next.getDate() + step * (t.recurrence.interval || 1));
        this.createTask({
          title: t.title, matter: t.matter, matterId: t.matterId,
          assignee: t.assignee, priority: t.priority, category: t.category,
          estimatedHours: t.estimatedHours, description: t.description,
          dueDate: next.toISOString().slice(0, 10),
          subtasks: (t.subtasks || []).map(s => ({ t: s.t, done: false })),
          recurrence: t.recurrence,
        });
      }
      return t;
    },

    deleteTask(id) {
      const idx = this.data.tasks.findIndex(x => x.id === id);
      if (idx < 0) return;
      const t = this.data.tasks[idx];
      this.data.tasks.splice(idx, 1);
      // Clean up reverse refs
      this.data.tasks.forEach(x => {
        x.blockedBy = x.blockedBy.filter(b => b !== id);
        x.blocks = x.blocks.filter(b => b !== id);
      });
      this._audit(id, 'Task Deleted', t.title);
      TkBus.emit('deleted', { task: t });
    },

    // Dependencies (#10 multi-blocker) -----------------------------------
    addBlocker(taskId, blockerId) {
      const t = this.data.tasks.find(x => x.id === taskId);
      const b = this.data.tasks.find(x => x.id === blockerId);
      if (!t || !b || taskId === blockerId) return;
      if (!t.blockedBy.includes(blockerId)) t.blockedBy.push(blockerId);
      if (!b.blocks.includes(taskId)) b.blocks.push(taskId);
      this._audit(taskId, 'Blocker Added', `Blocked by ${blockerId} (${b.title})`);
      TkBus.emit('updated', { task: t });
    },

    // Time tracking (#5) --------------------------------------------------
    startTimer(taskId) {
      if (this.data.activeTimer) this.stopTimer();
      this.data.activeTimer = { taskId, startedAt: Date.now() };
      this._audit(taskId, 'Timer Started', 'Active time tracking');
      TkBus.emit('timer.started', { taskId });
    },
    stopTimer() {
      const at = this.data.activeTimer;
      if (!at) return null;
      const t = this.data.tasks.find(x => x.id === at.taskId);
      const hrs = Math.max(0.1, Math.round(((Date.now() - at.startedAt) / 3600000) * 10) / 10);
      if (t) {
        t.loggedHours = Math.round((t.loggedHours + hrs) * 10) / 10;
        t.timeEntries.push({ id: uid('TE'), hours: hrs, logged: nowStamp(), actor: 'J. Saadein' });
        this._audit(at.taskId, 'Time Logged', `${hrs}h via timer`);
      }
      this.data.activeTimer = null;
      this._recomputeSla();
      TkBus.emit('timer.stopped', { taskId: at.taskId, hours: hrs });
      return { taskId: at.taskId, hours: hrs };
    },
    logTime(taskId, hours, note = '') {
      const t = this.data.tasks.find(x => x.id === taskId);
      if (!t) return;
      t.loggedHours = Math.round((t.loggedHours + hours) * 10) / 10;
      t.timeEntries.push({ id: uid('TE'), hours, logged: nowStamp(), actor: 'J. Saadein', note });
      this._audit(taskId, 'Time Logged', `${hours}h${note ? ' — ' + note : ''}`);
      this._recomputeSla();
      TkBus.emit('time.logged', { task: t });
    },

    // Bulk ops (#6) -------------------------------------------------------
    bulkSetStatus(ids, status) {
      ids.forEach(id => this.setStatus(id, status));
      TkBus.emit('bulk.updated', { ids, field: 'status', value: status });
    },
    bulkAssign(ids, assignee) {
      ids.forEach(id => this.updateTask(id, { assignee }));
      TkBus.emit('bulk.updated', { ids, field: 'assignee', value: assignee });
    },
    bulkPriority(ids, priority) {
      ids.forEach(id => this.updateTask(id, { priority }));
      TkBus.emit('bulk.updated', { ids, field: 'priority', value: priority });
    },
    bulkDelete(ids) {
      ids.forEach(id => this.deleteTask(id));
    },

    // Templates (#7) ------------------------------------------------------
    createFromTemplate(templateId, overrides = {}) {
      const tpl = this.data.templates.find(t => t.id === templateId);
      if (!tpl) return null;
      return this.createTask({
        title: overrides.title || tpl.name,
        category: tpl.category,
        estimatedHours: tpl.estimatedHours,
        description: tpl.description,
        subtasks: tpl.subtasks,
        matter: overrides.matter || 'Unassigned',
        matterId: overrides.matterId || '',
        assignee: overrides.assignee,
        priority: overrides.priority || 'medium',
        dueDate: overrides.dueDate || todayISO(),
        recurrence: overrides.recurrence || null,
      });
    },

    // Comments + @mentions (#20) -----------------------------------------
    addComment(taskId, body, actor = 'J. Saadein') {
      const t = this.data.tasks.find(x => x.id === taskId);
      if (!t) return;
      const mentions = (body.match(/@[A-Z]\.\s?\w+/g) || []).map(s => s.slice(1).trim());
      const c = { id: uid('CMT'), actor, body, ts: nowStamp(), mentions };
      t.comments.push(c);
      mentions.forEach(m => {
        this.data.mentions.unshift({ id: uid('MN'), taskId, taskTitle: t.title, actor, body, ts: c.ts, target: m, read: false });
      });
      this._audit(taskId, 'Comment Added', `${actor}: ${body.slice(0, 60)}${body.length > 60 ? '…' : ''}`);
      TkBus.emit('comment.added', { task: t, comment: c });
      return c;
    },
    markMentionRead(id) {
      const m = this.data.mentions.find(x => x.id === id);
      if (m) { m.read = true; TkBus.emit('mention.read', { id }); }
    },

    // Saved views (#4) ----------------------------------------------------
    saveView(name, filter) {
      const v = { id: uid('TV'), name, filter, system: false };
      this.data.savedViews.push(v);
      TkBus.emit('view.saved', v);
      return v;
    },
    deleteView(id) {
      const i = this.data.savedViews.findIndex(v => v.id === id && !v.system);
      if (i < 0) return;
      this.data.savedViews.splice(i, 1);
      TkBus.emit('view.deleted', { id });
    },

    // Analytics -----------------------------------------------------------
    workloadBalance() {
      const m = {};
      this.data.tasks.filter(t => t.status !== 'Done').forEach(t => {
        if (!m[t.assignee]) m[t.assignee] = { est: 0, remaining: 0, count: 0 };
        m[t.assignee].est += t.estimatedHours;
        m[t.assignee].remaining += Math.max(0, t.estimatedHours - t.loggedHours);
        m[t.assignee].count++;
      });
      return Object.entries(m).map(([name, v]) => {
        const cap = this.data.capacity[name] || 40;
        const utilization = Math.round((v.remaining / cap) * 100);
        return { assignee: name, ...v, capacity: cap, utilization, overbooked: utilization > 100 };
      }).sort((a, b) => b.utilization - a.utilization);
    },

    predictDueDate(category, estimatedHours) {
      const s = this.data.categorySla[category];
      if (!s) return null;
      const realisticHours = estimatedHours * (1 + (s.variance || 0) / 100);
      const days = Math.ceil(realisticHours / 6); // 6 billable hrs/day
      const d = new Date();
      d.setDate(d.getDate() + days);
      return { realisticHours: Math.round(realisticHours * 10) / 10, recommendedDate: d.toISOString().slice(0, 10), variance: s.variance || 0 };
    },

    riskFlags() {
      const now = new Date();
      const flags = [];
      this.data.tasks.forEach(t => {
        if (t.status === 'Done') return;
        const overdue = new Date(t.dueDate) < now;
        const blocked = t.blockedBy.length > 0;
        const overHours = t.loggedHours > t.estimatedHours;
        const score =
          (overdue ? 2 : 0) +
          (blocked ? 1 : 0) +
          (t.priority === 'high' ? 2 : t.priority === 'medium' ? 1 : 0) +
          (overHours ? 1 : 0);
        if (score >= 3) {
          flags.push({
            taskId: t.id, task: t, score,
            reasons: [
              overdue && 'Overdue',
              blocked && `Blocked by ${t.blockedBy.join(', ')}`,
              t.priority === 'high' && 'High priority',
              overHours && 'Over-budget on hours',
            ].filter(Boolean),
          });
        }
      });
      return flags.sort((a, b) => b.score - a.score);
    },

    burndown(matterId = null, days = 14) {
      const series = [];
      const end = new Date();
      for (let i = days - 1; i >= 0; i--) {
        const d = new Date(end); d.setDate(end.getDate() - i);
        const iso = d.toISOString().slice(0, 10);
        const pool = this.data.tasks.filter(t => !matterId || t.matterId === matterId);
        const remaining = pool.filter(t => {
          if (t.status === 'Done') return false;
          return new Date(t.dueDate) >= d;
        }).length;
        const done = pool.filter(t => t.status === 'Done').length;
        series.push({ date: iso, remaining, done });
      }
      return series;
    },

    utilizationReport() {
      const m = {};
      this.data.tasks.forEach(t => {
        if (!m[t.assignee]) m[t.assignee] = { logged: 0, billable: 0, admin: 0, completed: 0, active: 0 };
        m[t.assignee].logged += t.loggedHours;
        if (t.billable) m[t.assignee].billable += t.loggedHours;
        else m[t.assignee].admin += t.loggedHours;
        if (t.status === 'Done') m[t.assignee].completed++;
        else m[t.assignee].active++;
      });
      Object.values(m).forEach(v => {
        v.billablePct = v.logged ? Math.round((v.billable / v.logged) * 100) : 0;
      });
      return Object.entries(m).map(([name, v]) => ({ assignee: name, ...v, capacity: this.data.capacity[name] || 40 }));
    },

    reminders() {
      const now = Date.now();
      const out = [];
      this.data.tasks.forEach(t => {
        if (t.status === 'Done') return;
        const due = new Date(t.dueDate).getTime();
        const hrs = (due - now) / 3600000;
        const lead = this.data.reminderPolicy[t.priority] || 24;
        if (hrs <= lead && hrs > -72) {
          out.push({ taskId: t.id, task: t, hoursUntilDue: Math.round(hrs), overdue: hrs < 0 });
        }
      });
      return out.sort((a, b) => a.hoursUntilDue - b.hoursUntilDue);
    },
  };

  // ── Cross-platform bridges ─────────────────────────────────────────────
  // Docket: new deadline → auto-generate filing task with lead-time
  window.addEventListener('arbiter:docket.deadline.created', (ev) => {
    const dl = ev && ev.detail && (ev.detail.deadline || ev.detail);
    if (!dl || !dl.id) return;
    const due = new Date(dl.date);
    due.setDate(due.getDate() - 2);
    TaskStore.createTask({
      title: `Filing: ${dl.label || dl.title || dl.id}`,
      matter: dl.matter || 'Unassigned',
      matterId: dl.matterId || '',
      priority: dl.priority === 'critical' || dl.priority === 'high' ? 'high' : 'medium',
      category: 'Filing',
      estimatedHours: 4,
      description: `Auto-generated from Docket deadline ${dl.id}`,
      dueDate: due.toISOString().slice(0, 10),
      linkedDeadlines: [dl.id],
    });
  });

  // Persona touchpoint w/ follow-up → spawn task
  window.addEventListener('arbiter:persona.touchpoint.logged', (ev) => {
    const row = ev && ev.detail && (ev.detail.row || ev.detail);
    if (!row || !row.personId) return;
    if (!/follow[- ]?up|schedule|draft|prepare/i.test(row.subject + ' ' + (row.note || ''))) return;
    TaskStore.createTask({
      title: `Follow-up: ${row.subject}`,
      matter: 'Persona follow-up',
      matterId: row.personId,
      priority: 'medium',
      category: 'Admin',
      estimatedHours: 1,
      description: `Auto-generated from Persona touchpoint (${row.channel}).`,
      dueDate: (() => { const d = new Date(); d.setDate(d.getDate() + 3); return d.toISOString().slice(0, 10); })(),
    });
  });

  // SignDesk envelope stalled → spawn chase task
  window.addEventListener('arbiter:signdesk.envelope.stalled', (ev) => {
    const env = ev && ev.detail && (ev.detail.envelope || ev.detail);
    if (!env) return;
    TaskStore.createTask({
      title: `Chase signature: ${env.title || env.id}`,
      matter: env.matter || 'Unassigned',
      matterId: env.matterId || '',
      priority: 'high',
      category: 'Admin',
      estimatedHours: 0.5,
      description: `Auto-generated — SignDesk envelope ${env.id} stalled.`,
      dueDate: todayISO(),
    });
  });

  // Doc review requested → spawn review task
  window.addEventListener('arbiter:doc.review.requested', (ev) => {
    const doc = ev && ev.detail && (ev.detail.doc || ev.detail);
    if (!doc) return;
    TaskStore.createTask({
      title: `Review: ${doc.title || doc.name || doc.id}`,
      matter: doc.matter || 'Unassigned',
      matterId: doc.matterId || '',
      priority: 'medium',
      category: 'Review',
      estimatedHours: 2,
      description: `Auto-generated — doc needs review.`,
      dueDate: (() => { const d = new Date(); d.setDate(d.getDate() + 2); return d.toISOString().slice(0, 10); })(),
      linkedDocs: [doc.id],
    });
  });

  // ── React hook ──────────────────────────────────────────────────────────
  function useTaskStore(topics) {
    const [, force] = React.useReducer(x => x + 1, 0);
    React.useEffect(() => {
      const list = topics && topics.length ? topics : ['*'];
      const unsubs = list.map(t => TkBus.on(t, () => force()));
      return () => unsubs.forEach(u => u());
    }, []);
    return TaskStore.data;
  }

  window.__tkBus = TkBus;
  window.TaskStore = TaskStore;
  window.useTaskStore = useTaskStore;
})();
