botmux 3.13.0 → 3.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +1 -1
- package/README.md +25 -1
- package/dist/.runtime-build-id +1 -1
- package/dist/adapters/adopt-route.d.ts +58 -0
- package/dist/adapters/adopt-route.d.ts.map +1 -1
- package/dist/adapters/adopt-route.js +136 -0
- package/dist/adapters/adopt-route.js.map +1 -1
- package/dist/adapters/backend/capabilities.js +1 -1
- package/dist/adapters/backend/capabilities.js.map +1 -1
- package/dist/adapters/backend/herdr-backend.d.ts +1 -1
- package/dist/adapters/backend/herdr-backend.d.ts.map +1 -1
- package/dist/adapters/backend/herdr-backend.js +2 -1
- package/dist/adapters/backend/herdr-backend.js.map +1 -1
- package/dist/adapters/backend/riff-backend.d.ts +97 -0
- package/dist/adapters/backend/riff-backend.d.ts.map +1 -1
- package/dist/adapters/backend/riff-backend.js +380 -66
- package/dist/adapters/backend/riff-backend.js.map +1 -1
- package/dist/adapters/backend/sandbox.d.ts +8 -0
- package/dist/adapters/backend/sandbox.d.ts.map +1 -1
- package/dist/adapters/backend/sandbox.js +16 -2
- package/dist/adapters/backend/sandbox.js.map +1 -1
- package/dist/adapters/backend/tmux-backend.d.ts +12 -13
- package/dist/adapters/backend/tmux-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-backend.js +113 -53
- package/dist/adapters/backend/tmux-backend.js.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.d.ts +4 -3
- package/dist/adapters/backend/tmux-pipe-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.js +12 -9
- package/dist/adapters/backend/tmux-pipe-backend.js.map +1 -1
- package/dist/adapters/backend/zellij-backend.d.ts +2 -3
- package/dist/adapters/backend/zellij-backend.d.ts.map +1 -1
- package/dist/adapters/backend/zellij-backend.js +6 -13
- package/dist/adapters/backend/zellij-backend.js.map +1 -1
- package/dist/adapters/backend/zellij-observe-backend.d.ts +2 -1
- package/dist/adapters/backend/zellij-observe-backend.d.ts.map +1 -1
- package/dist/adapters/backend/zellij-observe-backend.js +6 -3
- package/dist/adapters/backend/zellij-observe-backend.js.map +1 -1
- package/dist/adapters/backend/zmx-backend.d.ts.map +1 -1
- package/dist/adapters/backend/zmx-backend.js +40 -18
- package/dist/adapters/backend/zmx-backend.js.map +1 -1
- package/dist/adapters/cli/claude-code.d.ts.map +1 -1
- package/dist/adapters/cli/claude-code.js +12 -1
- package/dist/adapters/cli/claude-code.js.map +1 -1
- package/dist/adapters/cli/codex.d.ts.map +1 -1
- package/dist/adapters/cli/codex.js +3 -2
- package/dist/adapters/cli/codex.js.map +1 -1
- package/dist/adapters/cli/dsh.d.ts +4 -0
- package/dist/adapters/cli/dsh.d.ts.map +1 -0
- package/dist/adapters/cli/dsh.js +96 -0
- package/dist/adapters/cli/dsh.js.map +1 -0
- package/dist/adapters/cli/fs-policy.d.ts.map +1 -1
- package/dist/adapters/cli/fs-policy.js +5 -0
- package/dist/adapters/cli/fs-policy.js.map +1 -1
- package/dist/adapters/cli/opencode.d.ts +52 -1
- package/dist/adapters/cli/opencode.d.ts.map +1 -1
- package/dist/adapters/cli/opencode.js +117 -76
- package/dist/adapters/cli/opencode.js.map +1 -1
- package/dist/adapters/cli/opencode2.d.ts +4 -0
- package/dist/adapters/cli/opencode2.d.ts.map +1 -0
- package/dist/adapters/cli/opencode2.js +137 -0
- package/dist/adapters/cli/opencode2.js.map +1 -0
- package/dist/adapters/cli/read-isolation.d.ts +1 -1
- package/dist/adapters/cli/read-isolation.d.ts.map +1 -1
- package/dist/adapters/cli/read-isolation.js +5 -2
- package/dist/adapters/cli/read-isolation.js.map +1 -1
- package/dist/adapters/cli/registry.d.ts +7 -1
- package/dist/adapters/cli/registry.d.ts.map +1 -1
- package/dist/adapters/cli/registry.js +19 -6
- package/dist/adapters/cli/registry.js.map +1 -1
- package/dist/adapters/cli/shared-hints.d.ts.map +1 -1
- package/dist/adapters/cli/shared-hints.js +13 -0
- package/dist/adapters/cli/shared-hints.js.map +1 -1
- package/dist/adapters/cli/types.d.ts +24 -3
- package/dist/adapters/cli/types.d.ts.map +1 -1
- package/dist/adapters/hook-command.d.ts +8 -0
- package/dist/adapters/hook-command.d.ts.map +1 -1
- package/dist/adapters/hook-command.js +11 -0
- package/dist/adapters/hook-command.js.map +1 -1
- package/dist/adapters/hook-installer.d.ts +16 -1
- package/dist/adapters/hook-installer.d.ts.map +1 -1
- package/dist/adapters/hook-installer.js +232 -2
- package/dist/adapters/hook-installer.js.map +1 -1
- package/dist/bot-registry.d.ts +116 -8
- package/dist/bot-registry.d.ts.map +1 -1
- package/dist/bot-registry.js +52 -4
- package/dist/bot-registry.js.map +1 -1
- package/dist/cli/pm2-start-transaction.d.ts +14 -0
- package/dist/cli/pm2-start-transaction.d.ts.map +1 -1
- package/dist/cli/pm2-start-transaction.js +25 -9
- package/dist/cli/pm2-start-transaction.js.map +1 -1
- package/dist/cli/restart-failure-notification.d.ts +54 -0
- package/dist/cli/restart-failure-notification.d.ts.map +1 -0
- package/dist/cli/restart-failure-notification.js +142 -0
- package/dist/cli/restart-failure-notification.js.map +1 -0
- package/dist/cli/restart-failure-owner.d.ts +20 -0
- package/dist/cli/restart-failure-owner.d.ts.map +1 -0
- package/dist/cli/restart-failure-owner.js +27 -0
- package/dist/cli/restart-failure-owner.js.map +1 -0
- package/dist/cli/restart-shutdown-preflight.d.ts +24 -0
- package/dist/cli/restart-shutdown-preflight.d.ts.map +1 -0
- package/dist/cli/restart-shutdown-preflight.js +105 -0
- package/dist/cli/restart-shutdown-preflight.js.map +1 -0
- package/dist/cli/send-dispatch.d.ts +26 -0
- package/dist/cli/send-dispatch.d.ts.map +1 -1
- package/dist/cli/send-dispatch.js +30 -0
- package/dist/cli/send-dispatch.js.map +1 -1
- package/dist/cli.d.ts +4 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +665 -399
- package/dist/cli.js.map +1 -1
- package/dist/codex-app-runner.js +38 -15
- package/dist/codex-app-runner.js.map +1 -1
- package/dist/codex-rpc-lifecycle.d.ts +14 -2
- package/dist/codex-rpc-lifecycle.d.ts.map +1 -1
- package/dist/codex-rpc-lifecycle.js +13 -3
- package/dist/codex-rpc-lifecycle.js.map +1 -1
- package/dist/core/ask-broker.d.ts +3 -0
- package/dist/core/ask-broker.d.ts.map +1 -1
- package/dist/core/ask-broker.js +29 -7
- package/dist/core/ask-broker.js.map +1 -1
- package/dist/core/ask-hook/registry.d.ts.map +1 -1
- package/dist/core/ask-hook/registry.js +4 -0
- package/dist/core/ask-hook/registry.js.map +1 -1
- package/dist/core/ask-types.d.ts +5 -1
- package/dist/core/ask-types.d.ts.map +1 -1
- package/dist/core/ask-types.js.map +1 -1
- package/dist/core/browser-restart.d.ts +112 -0
- package/dist/core/browser-restart.d.ts.map +1 -0
- package/dist/core/browser-restart.js +233 -0
- package/dist/core/browser-restart.js.map +1 -0
- package/dist/core/command-handler.d.ts +19 -11
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +237 -43
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/current-turn-provenance.d.ts.map +1 -1
- package/dist/core/current-turn-provenance.js +7 -27
- package/dist/core/current-turn-provenance.js.map +1 -1
- package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
- package/dist/core/dashboard-ipc-server.js +317 -10
- package/dist/core/dashboard-ipc-server.js.map +1 -1
- package/dist/core/dispatch-registry.d.ts.map +1 -1
- package/dist/core/dispatch-registry.js +6 -0
- package/dist/core/dispatch-registry.js.map +1 -1
- package/dist/core/dispatch-report-binding.d.ts +31 -0
- package/dist/core/dispatch-report-binding.d.ts.map +1 -0
- package/dist/core/dispatch-report-binding.js +88 -0
- package/dist/core/dispatch-report-binding.js.map +1 -0
- package/dist/core/doc-comment-prompt.d.ts +2 -0
- package/dist/core/doc-comment-prompt.d.ts.map +1 -1
- package/dist/core/doc-comment-prompt.js +6 -0
- package/dist/core/doc-comment-prompt.js.map +1 -1
- package/dist/core/host-overload-alert.d.ts +25 -1
- package/dist/core/host-overload-alert.d.ts.map +1 -1
- package/dist/core/host-overload-alert.js +69 -8
- package/dist/core/host-overload-alert.js.map +1 -1
- package/dist/core/local-terminal-opener.js +1 -1
- package/dist/core/local-terminal-opener.js.map +1 -1
- package/dist/core/managed-origin-capability.d.ts +7 -6
- package/dist/core/managed-origin-capability.d.ts.map +1 -1
- package/dist/core/managed-origin-capability.js +32 -1
- package/dist/core/managed-origin-capability.js.map +1 -1
- package/dist/core/passthrough-commands.d.ts.map +1 -1
- package/dist/core/passthrough-commands.js +3 -2
- package/dist/core/passthrough-commands.js.map +1 -1
- package/dist/core/plugins/materializer.d.ts.map +1 -1
- package/dist/core/plugins/materializer.js +1 -0
- package/dist/core/plugins/materializer.js.map +1 -1
- package/dist/core/producer-quiescence.d.ts +70 -0
- package/dist/core/producer-quiescence.d.ts.map +1 -0
- package/dist/core/producer-quiescence.js +90 -0
- package/dist/core/producer-quiescence.js.map +1 -0
- package/dist/core/raw-command-write-options.d.ts +10 -0
- package/dist/core/raw-command-write-options.d.ts.map +1 -0
- package/dist/core/raw-command-write-options.js +23 -0
- package/dist/core/raw-command-write-options.js.map +1 -0
- package/dist/core/raw-command-writer.d.ts +4 -0
- package/dist/core/raw-command-writer.d.ts.map +1 -1
- package/dist/core/raw-command-writer.js +15 -6
- package/dist/core/raw-command-writer.js.map +1 -1
- package/dist/core/reply-target.d.ts +11 -0
- package/dist/core/reply-target.d.ts.map +1 -1
- package/dist/core/reply-target.js +22 -7
- package/dist/core/reply-target.js.map +1 -1
- package/dist/core/report-session-relay.d.ts +53 -0
- package/dist/core/report-session-relay.d.ts.map +1 -0
- package/dist/core/report-session-relay.js +116 -0
- package/dist/core/report-session-relay.js.map +1 -0
- package/dist/core/session-discovery.d.ts +5 -0
- package/dist/core/session-discovery.d.ts.map +1 -1
- package/dist/core/session-discovery.js +13 -0
- package/dist/core/session-discovery.js.map +1 -1
- package/dist/core/session-group-birth.d.ts +7 -0
- package/dist/core/session-group-birth.d.ts.map +1 -0
- package/dist/core/session-group-birth.js +145 -0
- package/dist/core/session-group-birth.js.map +1 -0
- package/dist/core/session-manager.d.ts +16 -21
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +140 -21
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/trigger-session.d.ts.map +1 -1
- package/dist/core/trigger-session.js +18 -3
- package/dist/core/trigger-session.js.map +1 -1
- package/dist/core/types.d.ts +18 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/core/worker-pool.d.ts +63 -11
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +241 -13
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.d.ts +33 -0
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +900 -137
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/auth.d.ts +20 -0
- package/dist/dashboard/auth.d.ts.map +1 -1
- package/dist/dashboard/auth.js +86 -1
- package/dist/dashboard/auth.js.map +1 -1
- package/dist/dashboard/bot-payload.d.ts +5 -0
- package/dist/dashboard/bot-payload.d.ts.map +1 -1
- package/dist/dashboard/bot-payload.js +4 -1
- package/dist/dashboard/bot-payload.js.map +1 -1
- package/dist/dashboard/federation-spoke-api.d.ts.map +1 -1
- package/dist/dashboard/federation-spoke-api.js +27 -3
- package/dist/dashboard/federation-spoke-api.js.map +1 -1
- package/dist/dashboard/feedback-analytics-api.d.ts +6 -0
- package/dist/dashboard/feedback-analytics-api.d.ts.map +1 -0
- package/dist/dashboard/feedback-analytics-api.js +39 -0
- package/dist/dashboard/feedback-analytics-api.js.map +1 -0
- package/dist/dashboard/session-action-timeout.d.ts +3 -0
- package/dist/dashboard/session-action-timeout.d.ts.map +1 -0
- package/dist/dashboard/session-action-timeout.js +12 -0
- package/dist/dashboard/session-action-timeout.js.map +1 -0
- package/dist/dashboard/vc-consumer-profiles-api.d.ts +9 -3
- package/dist/dashboard/vc-consumer-profiles-api.d.ts.map +1 -1
- package/dist/dashboard/vc-consumer-profiles-api.js +2 -1
- package/dist/dashboard/vc-consumer-profiles-api.js.map +1 -1
- package/dist/dashboard/web/app.d.ts.map +1 -1
- package/dist/dashboard/web/app.js +48 -5
- package/dist/dashboard/web/app.js.map +1 -1
- package/dist/dashboard/web/bot-defaults-page.d.ts +4 -0
- package/dist/dashboard/web/bot-defaults-page.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults-page.js +273 -36
- package/dist/dashboard/web/bot-defaults-page.js.map +1 -1
- package/dist/dashboard/web/bot-defaults.d.ts +6 -0
- package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults.js.map +1 -1
- package/dist/dashboard/web/dashboard-routes.d.ts.map +1 -1
- package/dist/dashboard/web/dashboard-routes.js +1 -0
- package/dist/dashboard/web/dashboard-routes.js.map +1 -1
- package/dist/dashboard/web/feedback-page.d.ts +3 -0
- package/dist/dashboard/web/feedback-page.d.ts.map +1 -0
- package/dist/dashboard/web/feedback-page.js +34 -0
- package/dist/dashboard/web/feedback-page.js.map +1 -0
- package/dist/dashboard/web/groups-page.d.ts.map +1 -1
- package/dist/dashboard/web/groups-page.js +7 -2
- package/dist/dashboard/web/groups-page.js.map +1 -1
- package/dist/dashboard/web/i18n.d.ts.map +1 -1
- package/dist/dashboard/web/i18n.js +114 -22
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard/web/team-federation-page.d.ts.map +1 -1
- package/dist/dashboard/web/team-federation-page.js +26 -2
- package/dist/dashboard/web/team-federation-page.js.map +1 -1
- package/dist/dashboard/web/team-federation.d.ts +19 -0
- package/dist/dashboard/web/team-federation.d.ts.map +1 -1
- package/dist/dashboard/web/team-federation.js +3 -0
- package/dist/dashboard/web/team-federation.js.map +1 -1
- package/dist/dashboard/web/update-action.d.ts +8 -0
- package/dist/dashboard/web/update-action.d.ts.map +1 -1
- package/dist/dashboard/web/update-action.js +10 -0
- package/dist/dashboard/web/update-action.js.map +1 -1
- package/dist/dashboard/web/vc-consumer-profiles-section.d.ts.map +1 -1
- package/dist/dashboard/web/vc-consumer-profiles-section.js +58 -9
- package/dist/dashboard/web/vc-consumer-profiles-section.js.map +1 -1
- package/dist/dashboard-web/app.js +1 -1
- package/dist/dashboard-web/chunks/bot-defaults-page-4RENHE7J.js +10 -0
- package/dist/dashboard-web/chunks/chunk-2WQDS65D.js +1 -0
- package/dist/dashboard-web/chunks/{chunk-CU4SUKK3.js → chunk-6O7KXFD2.js} +1 -1
- package/dist/dashboard-web/chunks/chunk-G5XGBCM6.js +1 -0
- package/dist/dashboard-web/chunks/{chunk-6JTZJRQJ.js → chunk-Q2MT4VWH.js} +15 -15
- package/dist/dashboard-web/chunks/{chunk-5QJB24I2.js → chunk-U3ZFSO7E.js} +1 -1
- package/dist/dashboard-web/chunks/connectors-page-2KZO5KSJ.js +1 -0
- package/dist/dashboard-web/chunks/feedback-page-CLVTOLLO.js +1 -0
- package/dist/dashboard-web/chunks/groups-page-HLASRTSY.js +8 -0
- package/dist/dashboard-web/chunks/{insights-page-EVGGJI5L.js → insights-page-4RPU2CRU.js} +1 -1
- package/dist/dashboard-web/chunks/{monitor-room-HRGR2ENP.js → monitor-room-OTKQ2CXK.js} +1 -1
- package/dist/dashboard-web/chunks/monitoring-page-IJPUB6JT.js +2 -0
- package/dist/dashboard-web/chunks/office-page-QSR3J44Y.js +1 -0
- package/dist/dashboard-web/chunks/overview-page-6OK63V4V.js +1 -0
- package/dist/dashboard-web/chunks/roles-page-6NWJMOB5.js +1 -0
- package/dist/dashboard-web/chunks/schedules-page-6I3LNXD4.js +1 -0
- package/dist/dashboard-web/chunks/{sessions-page-DXBCDWCS.js → sessions-page-B2TXGJDO.js} +1 -1
- package/dist/dashboard-web/chunks/settings-page-6KJADSC6.js +2 -0
- package/dist/dashboard-web/chunks/{skills-page-2QAVB2SA.js → skills-page-M2Q6L5CB.js} +1 -1
- package/dist/dashboard-web/chunks/team-federation-page-7I7FDE3B.js +1 -0
- package/dist/dashboard-web/chunks/{v3-page-AY35LKCX.js → v3-page-HQXRL65L.js} +1 -1
- package/dist/dashboard-web/chunks/whiteboards-page-LQKC4TAZ.js +1 -0
- package/dist/dashboard-web/style.css +35 -0
- package/dist/dashboard.js +199 -12
- package/dist/dashboard.js.map +1 -1
- package/dist/desktop/shared/shell-path-probes.d.ts +1 -1
- package/dist/desktop/shared/shell-path-probes.js +2 -2
- package/dist/desktop/shared/shell-path-probes.js.map +1 -1
- package/dist/dsh-runner.d.ts +3 -0
- package/dist/dsh-runner.d.ts.map +1 -0
- package/dist/dsh-runner.js +666 -0
- package/dist/dsh-runner.js.map +1 -0
- package/dist/global-config.d.ts +24 -0
- package/dist/global-config.d.ts.map +1 -1
- package/dist/global-config.js +35 -0
- package/dist/global-config.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +25 -6
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +25 -6
- package/dist/i18n/zh.js.map +1 -1
- package/dist/im/lark/ask-card.d.ts +3 -1
- package/dist/im/lark/ask-card.d.ts.map +1 -1
- package/dist/im/lark/ask-card.js +61 -5
- package/dist/im/lark/ask-card.js.map +1 -1
- package/dist/im/lark/card-builder.d.ts.map +1 -1
- package/dist/im/lark/card-builder.js +13 -6
- package/dist/im/lark/card-builder.js.map +1 -1
- package/dist/im/lark/card-handler.d.ts +2 -1
- package/dist/im/lark/card-handler.d.ts.map +1 -1
- package/dist/im/lark/card-handler.js +145 -5
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/im/lark/event-dispatcher.d.ts +18 -0
- package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
- package/dist/im/lark/event-dispatcher.js +36 -9
- package/dist/im/lark/event-dispatcher.js.map +1 -1
- package/dist/im/lark/md-card.d.ts +18 -0
- package/dist/im/lark/md-card.d.ts.map +1 -1
- package/dist/im/lark/md-card.js +21 -0
- package/dist/im/lark/md-card.js.map +1 -1
- package/dist/im/lark/relay-target-routing.d.ts.map +1 -1
- package/dist/im/lark/relay-target-routing.js +3 -2
- package/dist/im/lark/relay-target-routing.js.map +1 -1
- package/dist/im/lark/reply-mode-command.d.ts.map +1 -1
- package/dist/im/lark/reply-mode-command.js +19 -8
- package/dist/im/lark/reply-mode-command.js.map +1 -1
- package/dist/im/lark/skill-feedback-card.d.ts +15 -0
- package/dist/im/lark/skill-feedback-card.d.ts.map +1 -0
- package/dist/im/lark/skill-feedback-card.js +149 -0
- package/dist/im/lark/skill-feedback-card.js.map +1 -0
- package/dist/services/bot-config-store.d.ts +10 -1
- package/dist/services/bot-config-store.d.ts.map +1 -1
- package/dist/services/bot-config-store.js +103 -3
- package/dist/services/bot-config-store.js.map +1 -1
- package/dist/services/bridge-fallback-gate.d.ts +14 -0
- package/dist/services/bridge-fallback-gate.d.ts.map +1 -1
- package/dist/services/bridge-fallback-gate.js +15 -0
- package/dist/services/bridge-fallback-gate.js.map +1 -1
- package/dist/services/codex-reasoning-effort.d.ts +9 -0
- package/dist/services/codex-reasoning-effort.d.ts.map +1 -0
- package/dist/services/codex-reasoning-effort.js +23 -0
- package/dist/services/codex-reasoning-effort.js.map +1 -0
- package/dist/services/codex-service-tier.d.ts +1 -1
- package/dist/services/codex-service-tier.d.ts.map +1 -1
- package/dist/services/codex-transcript.d.ts +9 -0
- package/dist/services/codex-transcript.d.ts.map +1 -1
- package/dist/services/codex-transcript.js +13 -6
- package/dist/services/codex-transcript.js.map +1 -1
- package/dist/services/feed-group-tagger.d.ts +15 -0
- package/dist/services/feed-group-tagger.d.ts.map +1 -0
- package/dist/services/feed-group-tagger.js +348 -0
- package/dist/services/feed-group-tagger.js.map +1 -0
- package/dist/services/feedback-analytics.d.ts +82 -0
- package/dist/services/feedback-analytics.d.ts.map +1 -0
- package/dist/services/feedback-analytics.js +95 -0
- package/dist/services/feedback-analytics.js.map +1 -0
- package/dist/services/feedback-outbox.d.ts +24 -0
- package/dist/services/feedback-outbox.d.ts.map +1 -0
- package/dist/services/feedback-outbox.js +12 -0
- package/dist/services/feedback-outbox.js.map +1 -0
- package/dist/services/feedback-policy-resolver.d.ts +56 -0
- package/dist/services/feedback-policy-resolver.d.ts.map +1 -0
- package/dist/services/feedback-policy-resolver.js +156 -0
- package/dist/services/feedback-policy-resolver.js.map +1 -0
- package/dist/services/feedback-policy.d.ts +41 -0
- package/dist/services/feedback-policy.d.ts.map +1 -0
- package/dist/services/feedback-policy.js +102 -0
- package/dist/services/feedback-policy.js.map +1 -0
- package/dist/services/feedback-webhook-dispatcher.d.ts +76 -0
- package/dist/services/feedback-webhook-dispatcher.d.ts.map +1 -0
- package/dist/services/feedback-webhook-dispatcher.js +237 -0
- package/dist/services/feedback-webhook-dispatcher.js.map +1 -0
- package/dist/services/grant-prefs-store.d.ts +3 -0
- package/dist/services/grant-prefs-store.d.ts.map +1 -1
- package/dist/services/grant-prefs-store.js +30 -1
- package/dist/services/grant-prefs-store.js.map +1 -1
- package/dist/services/groups-store.d.ts +14 -0
- package/dist/services/groups-store.d.ts.map +1 -1
- package/dist/services/groups-store.js +23 -0
- package/dist/services/groups-store.js.map +1 -1
- package/dist/services/local-cli-opener.d.ts +1 -1
- package/dist/services/local-cli-opener.d.ts.map +1 -1
- package/dist/services/local-cli-opener.js +2 -0
- package/dist/services/local-cli-opener.js.map +1 -1
- package/dist/services/prompt-context-store.d.ts +29 -0
- package/dist/services/prompt-context-store.d.ts.map +1 -0
- package/dist/services/prompt-context-store.js +205 -0
- package/dist/services/prompt-context-store.js.map +1 -0
- package/dist/services/session-group-avatar.d.ts +6 -0
- package/dist/services/session-group-avatar.d.ts.map +1 -0
- package/dist/services/session-group-avatar.js +96 -0
- package/dist/services/session-group-avatar.js.map +1 -0
- package/dist/services/session-group-title.d.ts +47 -0
- package/dist/services/session-group-title.d.ts.map +1 -0
- package/dist/services/session-group-title.js +226 -0
- package/dist/services/session-group-title.js.map +1 -0
- package/dist/services/session-groups-store.d.ts +30 -0
- package/dist/services/session-groups-store.d.ts.map +1 -0
- package/dist/services/session-groups-store.js +132 -0
- package/dist/services/session-groups-store.js.map +1 -0
- package/dist/services/session-store.d.ts +58 -0
- package/dist/services/session-store.d.ts.map +1 -1
- package/dist/services/session-store.js +174 -0
- package/dist/services/session-store.js.map +1 -1
- package/dist/services/skill-feedback-store.d.ts +252 -0
- package/dist/services/skill-feedback-store.d.ts.map +1 -0
- package/dist/services/skill-feedback-store.js +795 -0
- package/dist/services/skill-feedback-store.js.map +1 -0
- package/dist/services/skill-registry-store.d.ts +23 -0
- package/dist/services/skill-registry-store.d.ts.map +1 -1
- package/dist/services/skill-registry-store.js +93 -7
- package/dist/services/skill-registry-store.js.map +1 -1
- package/dist/services/team-store.d.ts +4 -0
- package/dist/services/team-store.d.ts.map +1 -1
- package/dist/services/team-store.js +16 -0
- package/dist/services/team-store.js.map +1 -1
- package/dist/services/traex-transcript.d.ts +32 -4
- package/dist/services/traex-transcript.d.ts.map +1 -1
- package/dist/services/traex-transcript.js +116 -8
- package/dist/services/traex-transcript.js.map +1 -1
- package/dist/services/trigger-types.d.ts +1 -1
- package/dist/services/trigger-types.d.ts.map +1 -1
- package/dist/services/trigger-types.js +2 -2
- package/dist/services/trigger-types.js.map +1 -1
- package/dist/services/turn-completion-events.d.ts +57 -0
- package/dist/services/turn-completion-events.d.ts.map +1 -0
- package/dist/services/turn-completion-events.js +179 -0
- package/dist/services/turn-completion-events.js.map +1 -0
- package/dist/services/vc-meeting-consumer-isolation.d.ts +21 -12
- package/dist/services/vc-meeting-consumer-isolation.d.ts.map +1 -1
- package/dist/services/vc-meeting-consumer-isolation.js +25 -19
- package/dist/services/vc-meeting-consumer-isolation.js.map +1 -1
- package/dist/services/vc-meeting-consumer-profile-bootstrap.d.ts +8 -2
- package/dist/services/vc-meeting-consumer-profile-bootstrap.d.ts.map +1 -1
- package/dist/services/vc-meeting-consumer-profile-bootstrap.js +18 -10
- package/dist/services/vc-meeting-consumer-profile-bootstrap.js.map +1 -1
- package/dist/setup/bot-config-editor.d.ts.map +1 -1
- package/dist/setup/bot-config-editor.js +6 -0
- package/dist/setup/bot-config-editor.js.map +1 -1
- package/dist/setup/cli-availability.d.ts +2 -1
- package/dist/setup/cli-availability.d.ts.map +1 -1
- package/dist/setup/cli-availability.js +2 -1
- package/dist/setup/cli-availability.js.map +1 -1
- package/dist/setup/cli-selection.d.ts +8 -0
- package/dist/setup/cli-selection.d.ts.map +1 -1
- package/dist/setup/cli-selection.js +31 -0
- package/dist/setup/cli-selection.js.map +1 -1
- package/dist/setup/ensure-fonts.d.ts +5 -0
- package/dist/setup/ensure-fonts.d.ts.map +1 -1
- package/dist/setup/ensure-fonts.js +26 -1
- package/dist/setup/ensure-fonts.js.map +1 -1
- package/dist/setup/lark-scopes.json +3 -1
- package/dist/setup/open-platform-automation.d.ts +1 -1
- package/dist/setup/open-platform-automation.d.ts.map +1 -1
- package/dist/setup/open-platform-automation.js +15 -3
- package/dist/setup/open-platform-automation.js.map +1 -1
- package/dist/skills/definitions.d.ts +1 -1
- package/dist/skills/definitions.d.ts.map +1 -1
- package/dist/skills/definitions.js +9 -2
- package/dist/skills/definitions.js.map +1 -1
- package/dist/types.d.ts +10 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/user-token.d.ts +38 -0
- package/dist/utils/user-token.d.ts.map +1 -1
- package/dist/utils/user-token.js +76 -1
- package/dist/utils/user-token.js.map +1 -1
- package/dist/utils/web-terminal-scroll.d.ts +27 -0
- package/dist/utils/web-terminal-scroll.d.ts.map +1 -0
- package/dist/utils/web-terminal-scroll.js +60 -0
- package/dist/utils/web-terminal-scroll.js.map +1 -0
- package/dist/vc-agent/polling-source.d.ts +70 -0
- package/dist/vc-agent/polling-source.d.ts.map +1 -1
- package/dist/vc-agent/polling-source.js +115 -0
- package/dist/vc-agent/polling-source.js.map +1 -1
- package/dist/worker.js +237 -76
- package/dist/worker.js.map +1 -1
- package/dist/workflows/definition.d.ts +22 -22
- package/dist/workflows/events/payloads.d.ts +8 -8
- package/dist/workflows/events/schema.d.ts +20 -20
- package/dist/workflows/migration/v2-run-archive-schema.d.ts +20 -20
- package/package.json +1 -1
- package/dist/dashboard-web/chunks/bot-defaults-page-NQJFJ45Z.js +0 -10
- package/dist/dashboard-web/chunks/chunk-KEEYQ3WF.js +0 -1
- package/dist/dashboard-web/chunks/connectors-page-HADHZXXZ.js +0 -1
- package/dist/dashboard-web/chunks/groups-page-5TYF46RS.js +0 -8
- package/dist/dashboard-web/chunks/monitoring-page-LBU7TTTW.js +0 -2
- package/dist/dashboard-web/chunks/office-page-DF6RRBMN.js +0 -1
- package/dist/dashboard-web/chunks/overview-page-ZB6QH2EX.js +0 -1
- package/dist/dashboard-web/chunks/roles-page-ZBZGHIIF.js +0 -1
- package/dist/dashboard-web/chunks/schedules-page-NQVQC3QY.js +0 -1
- package/dist/dashboard-web/chunks/settings-page-E7NN4NVQ.js +0 -2
- package/dist/dashboard-web/chunks/team-federation-page-VGWL53AE.js +0 -1
- package/dist/dashboard-web/chunks/whiteboards-page-BNWUU4KG.js +0 -1
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session-group avatar branding (p2pMode='group').
|
|
3
|
+
*
|
|
4
|
+
* Zero-permission visual "tag": every session group gets a distinctive
|
|
5
|
+
* built-in avatar (purple gradient + white bot bubble), so bot session groups
|
|
6
|
+
* are recognizable at a glance in the chat list. This works with scopes
|
|
7
|
+
* botmux already holds (im image upload + chat update, and the bot owns its
|
|
8
|
+
* session groups) — no tenant tag catalog, no user OAuth, no console visit.
|
|
9
|
+
*
|
|
10
|
+
* The PNG ships inline (base64, ~3.4KB). It is uploaded once per bot with
|
|
11
|
+
* image_type='avatar' and the resulting image_key is cached in
|
|
12
|
+
* `${dataDir}/session-avatar-cache-${appId}.json`; every birth then only
|
|
13
|
+
* costs one chat.update. All paths are best-effort fire-and-forget.
|
|
14
|
+
*/
|
|
15
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
16
|
+
import { join, dirname } from 'node:path';
|
|
17
|
+
import { getBot, getBotClient } from '../bot-registry.js';
|
|
18
|
+
import { config } from '../config.js';
|
|
19
|
+
import { logger } from '../utils/logger.js';
|
|
20
|
+
/** 360×360 official botmux "bm" gradient logo on white (user-picked option A). */
|
|
21
|
+
const AVATAR_PNG_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAAWgAAAFoCAIAAAD1h/aCAACIbElEQVR42u39ebzt+VUWCD/P+v723me8Q9WtuTJU5onMgQwGiAKCCKI2UUBJ+zqAgqitQIvS2AqCvP2+OL3qx6Eb0AalISAIhECCYBIImclcFEmqKjXm1q07n3P2/n3X03+s9f3tU8LbDEkl9576LkOsnDr33HvP2Xv91nrWM1ASevXq1ev3Uta/Bb169eqNo1evXr1x9OrVqzeOXr169cbRq1ev3jh69erVqzeOXr169cbRq1ev3jh69erVG0evXr164+jVq1ev3jh69erVG0evXr164+jVq1dvHL169eqNo1evXr164+jVq1dvHL169eqNo1evXr1x9OrVqzeOXr169cbRq1evXr1x9OrVqzeOXr169cbRq1ev3jh69erVG0evXr169cbRq1ev3jh69erVG0evXr164+jVq1dvHL169erVG0evXr164+jVq1dvHL169eqNo1evXr1x9OrVq1dvHL169eqNo1evXr1x9OrVqzeOXr169cbRq1ev3jh69erVqzeOXr169cbRq1ev3jh69erVG0evXr164+jVq1ev3jh69erVG0evXr164+jVq1dvHL169eqNo1evXr164+jVq1dvHL169eqNo1evXr1x9OrVqzeOXr169eqNo1evXr1x9OrVqzeOXr169cbRq1ev3jh69erVG0evXr169cbRq1ev3jh69erVG0evXr164+jVq1dvHL169erVG0evXr164+jVq1dvHL169eqNo1evXr1x9OrVq1dvHL169eqNo1evXr1x9OrVqzeOXr169cbRq1evXr1x9OrVqzeOXr169cbRq1ev3jh69ep1FGro34LfvgQd+m8AJACAIAD2b1Cv3jh6Tc1C7Z8JsrWJ31Lu+flW+net12OxqPV75THcMRwQWA5/RJfO6uyDdbmncQkzzRbcPDbsnOTGDqxEP5Gc7jAD+87Xq08cj6GWIchzcBiXungvP/xr/ok7ePounL5Pp+8fx5W8gjPOZhq2tH1itnUM19+ia59cn/nS2Y1P0mwBgHWElbbO9OrVJ44jPGWo7RoPfUR3vEW3/wpP/6ZOP6hLl1c00CSDKJhkEjBKdYnlPvYuiWW47pbhSc8ZXvhFevbn4tqbCgCvMOsISK/eOI5u14jl4qGP4Vd/SB96Ax64pw4bqlaHOQS4a6xeq0RIqpQEkaoS4IBXrZaAZqDdeJu96n+YveyP4fgNlAD1zaVXbxxHbzcRzHDxIb39h/men/J7Plbnu8IMkkPuzlrhUnV3l0hAo9b9wuUOEiwGDCTtYGnLC/bEpw1/8DX8gq8pLJAnttqrV28cR2HQgIHQh9+on/snfuajqLNaNlVX7qIIVbkkZ3VVuStgU1RJYHUJckkAQYNgRQAgGC6c07icfe4f2frTfxc3PQle2W8uvXrjuOorzh++0i/8f/DmH3Af6mzLK1RjGwFdcncXAYxe5RghARJccnD0qWkAABn/Ci6pgkYnLpyxW5+09Re/q7zgC+gVtI6Y9uqN4+qdNSpYcOkMXvf38Os/W8vxSvpY4ZRIChXuDifk7oK7nKrRF+DulFQlCQKjF1SJYJXkkMElgGXOg31baP6ab59/0Z8zeaOE9OrVG8dVt6HQcPFB//Fv4R2/6ovjdRzdEVMGHJLgiHe+qruDAqq8SrGtQHChtu+VQEnO4HHEfQYijBRoBeOSq4sbr/m24Y//NavVSj+19DpaZY+RrrF/Vv/lW3HXO+rWte4VUECXIoNVjiCNSg5RkruUCwkkuOewAVBgNBo5JYkuyAUIFXL31dKNPj+2/Pffu3rdv/NSGtO0V6/eOK6OriGQuHzWf/Kb/aNv18Y10ghSNBhAIW6sUuIYDk7yFElKUqkc8ERBA++Qu9xdUown+ekOFwSNEsznx/a//3uWv/Izo/Xe0as3jquqc8CFt3wf7/glbezWui/ID+GV0R8c9HW7ANSEKoo1Jj8ztSwBowoQ5K09RUOJs4sEQV4roBH7/+bbVne+v5rBa3+99eqN4+pYUvSRn8F7f8w3T6quaAJJEkaBIpRNQmqaV4lxZPFsGWRQP0S5GEOGRFFOegwrIEDGZ3quMw6uRgwDPvHA8t9+e11emvahXr1647iyoY1LD/Cd/wfKBmiEySnG+hFdgwigk6RibxGpGAyYZDFJRFBBBYEBl0pOiiAC3YCEdm3JScdV3ff3vWyufu2N+6/7gdFKbxy9euO4GgCOd/8AHrzTh+3AMkBRcU4REW98i9aRkwghkIKC5pU6ewEQRTNILhfkDjk8GowTzjzHCoGuQtLoGh21UrODH//Xy4fucbPeO3r1xnFljxv3vVO3/6yGTXmF0Ur0iuwYokSRLsb9JEYLIwDSFIhnXFjNlNNHsD4QtxZ3uFMgEBBJfg13OdyTOeaSdo6Vez5+8NPfvwTUUdJevXFcqUXUEbe/Fvvn831tydsiLXHOQD8TxaAQ40a+/xvICUqgO0GRSekgc2IhABdEGQF4/M5UzB3uBMxIg6TtXb75p8sDd3opDVPt1as3jitr3CAefLfuepOwqO5tFVEMGiAIptiVZF5LBEcqUTwAjERJpVxe4gsptxE6o/IIS9nUewIybSo30iXaeO9HVm9/PRGkj169euO4AtGNe34JF8+Kc8q5nkNoNFiMHtkxnFCSwYKmAagBHvHx5HCQFBBISbBOHRKVX15IDupkUZoNJjqF3PYP9n/xx2pdspT8pF69euO4gtCNvTP6yFsw7IIKvCJuKLTQjTDvp7LoBkxaV/DBoGB/pLVGfOohglcVYDSRQenwuL14zCz01qjS3Fjuqq5x9PmW3/6+gw+/c2xrTa9evXFcSfXAe3D5Acw2TFOnUMAczkQiPEYRQXlpZZxEqBhNQIc5PdYYdycBWgwjcXDJOSPmi5DKJmICsvHJkOvO6F7munhx//2/Oh76hb169cZxJRQB6ONvlgVUYXFntdYQGueC8ORlIC4hueIEKDFp2cQESWP+aPNIUEUVdDEyvqQCRWnG6LELKREUN4MNnG/ijg8eoEveevXGcSUtKiCxvMyzv4EqCLQYNOKQ0jif2SyypwhGR9A5QrXS2OVN0pbzSGAYoCg10rmSla5YdpgyOYV8NpadwFlZQGm+0L0fGc6dEa3fVnr1xnGl9A0AOHcn/BxVkoe13goYXcPjUJK/JHVsrhTLgqQIl4dVIKevwPj8Fr5iMaUohHRBMBMUzh1MJno0HaMRQK0i9dB9fv+d3peVXr1xXDHlAHDxPl9dhg1qsCWTOZ6VNxUFP7StG4DHp8abHaFkEwGIppwd4pwb24rycNKGlOSaMu4rnl+FpOWNJj7hwvnxzOkR6BNHr944rqSJ4/KD3LssWJOa5CoR7qES5VyfS9AoXyQBa7NGO6U0z57AONYsdIpgfnHLf9QkvVeAJYzPE+Xw9uV0cHl56eH+wuvVG8eV85cJaPMix4OqIJYDLo93PeAyxgJTEfpVNHIo2qoB0FqvYZDCQuMSgvqYVhwQHUzPLyUimtYesRfFkdflcuU5N+DWUvYuDvH79erVG8eVUuMlydDom3kPjYuJ6B52G87QyFPmPHQlQXYMpZg+5bQTSKKkbIRxYHYYD0WKYw2AhHI2OatQGBRCNEh+/ux4aELq1evqqyMVARnrx/JSylk5mfPkWzeBB7k8pWjNLjR3ltg0PKHLdhjx6dTS0lWyi6xRjbQwFtoQgwRBwLADav9KFLE8aFNJr169cXzG2wYJl+oqLqNeQ4KWepO8xrrn6TTwzUhXCouNGvxRMi1EHe0u06YWkh7oBqKBSGBsKAAmT1IIztZCOHWWbGEO994yevVV5cqaOCihirWNEzEjVKXvRpA45BM1C4+ggCItedSOIvlBBnesgZ7RGgTkFBOXXiWbLOcbNdvSZJqmr+m0z/Tq1SeOK6p9OFiANPprtxCf7rNKiZq3D7rgoMLkJ9/eAJmuPc1VVJJgHp9GSBSCUpZkc6IxUWNGoZFyd7SGheks26tXbxxXVuMgqrsAFwXVBnx6ytTkYAVyIslDCJOdEXZeeaeNdsEJyiAmA68YSVo2Ux5nPRghggfbjKgSg4UuedxmMelpe/Xqq8pnvoiGS0KOiEpS2zuqK7OXwGbn1faScAj1iZqeMKcrvX6YywhcSgMvTdQPiZGpQCKkLdl0uGaa5rQhIr0+rLeOXn3iuLIQDgiqAKHa9o4KD/Z4FeSozeOvumpSMuQRMZ17Ct2brnUNhSQ4oaSUMzDYZJbTk0pKtStukksFwZt6dm3z0f7EvXr1ieMKmDjyDhvpjRWqkMscE6IhAXlwARRtRdNdNu8fE+MLDTcV4D4J5kMKK0i25nn4BLEqmB7NIigvKppaRT/H9uoTx5UzceTbOxFLF2rz/Is7q0TPuyyStYVHgKOZtwRRqJrErxbakwxHoIdULixMp/0lwxJkeb6ZugmYowhRIjiyU7969cZxRTUPAu6oguVFNHqHHKpB+IxDamN/jYdUcM0EjBAqLL1Bw1EwIlXgLW2luf7EXbfRx0It3ygfweCAQ+agpT9Qj67v1RvHFbeuCKrSCA0RAS1VcVpDKuAxgBA1tbKocoTYvoW2OcPzKzoOvOWxkHS4POFTR15R3EUaM6k6aGjIrpM3WiqlMzSwCfJ79eqN44oBOtzpLs9LSkCkCkJHwp9AbZQN5SVGAIJUGgdaJMUzieKpj02hS+KjKZgLG2OtuWXI5JXw9Yh4hsyQg2lyA+mDR6/eOK4srGMUVb2654aCXFIqJHBUenEIoXOFPE0Dw19UsApINW4kbVmhyxuvHI3qAUd6B3omVecuk4Qv5koDrMkhfdro1RvHFVcVGOWgV8EdDvfQrnjExXu8yUP5lqTw9AVziRElDXlVuvs0UCOoXgmoxpThCaqECaF7nITThTAbBCdaqSRjZi/06tUbx5XVOGK48HYWCRfAJGY0gWy+/ZXZCMjUpmkSSZ1sNhY6EAjGpGvRJGnL/5UtQzAkh6OtMIzrrTc6mfrE0as3jiuuXKhySDUSokXBPdVu0RYQF1sXRA9RnFyeGw1dIUVxEmIzJo5VJm3OeSiurTUOTVeUdP+JUcXWzI0gd/SBo1dvHFcmxuGRlBRQqMfxVZCDDiDQDXnYFgdAkVyPVKYEmonWTdLep0WqBBnEAVNSydEmC6B5/wgk3cjJPT1gDk9lPzpztFdvHFdKyyBQHaNUgh4KpNso6Z6IpYc4Bc2YI9TwAX+6g4TocoAi0bJnQVUlKqq1LqWtIIzphBP0GbH3gY64pYYl9PdkZ4726o3jSmsfgrtG+ZhXETonsrkjjUDRhCdJD3OEKI55V2GMIcxI2AyH9MyB03R+rSS9HVSEFLE1MR3b8sLsT9kzesvo1RvHFVYVqPChqelrWOfkfEFAtdmKulwy0eFNzMa054q9RuHR0e6oiYxOKdNKGVv+AgIOGtvvE45khGCW9+CiZpzcV5VP0YyJ9oNeR/YenuemUB32ht0bx29b66gDVDEoXu7TrBGcC7QbakhUKCkpomzhBpwSWPLrHtLgp+qt0crbQWV9exVC9aa06AjbUffsLvrv/8S9fj8TZbi6ldQl/5bvIw915Ef+u9rmPbJ/93vjwOFni6pQpSqNjnUMfROoytMxWKlMAdJ9Q2unr0biaudYTObDk1/ptLBQU5p9YBg69JKNDAXk0hIfJQVbi3l7/a7HCgDWQsRD1r23wrkDXR51qeLSkiO5X+USqdlgc/iiYHeGnYHbA7ZnGA45oTQEu/8MHvOrSkyjVapE6OirgsCR6IPSqMtb6oFc1owFg+7VwqiV19lmBeQga/aWw42qwR8kKEczFLN2tiWnFaexPh45Q/f6f2wZwdm39vYehfsv6GMXeedZ3X2JDx7o/j1cHLEcUV1lLisgYUYrrlHu2NjgsYVOznlyAzdv4MaFnrDLWzdwfLbWG3qL5+r1WGwck/uFewAZ7f+CwZXEjVxJEFqTIHax0S4YdqSaOONxQCXph1KaLK8nmUetpJynWQct/iwWAhgcdiKFNXMw9t7xO+4jRhQCwNl93bnPN97uH7nMBy7h/gtaVcxmbgOLieQAEcIIVqPJilQJaSisIx6GzhygXsAKkHBsS48/iadt6hm7dtscN840L+zt47HbOOIl50D1ENdLQCWDN+oCghYugm3ukGdKUmOWh+YVsePAwyGwhnotuVusPv1zyObjMlPCdtRkCCpIwKtBIk2rMBL0R8J5vR4BQzhIGUng8oh33oN3PIi33Y/793R+X1ppe4GNGbdmYMmUb0Bu64ZNskpGmBkY5ktm0GDYNEGqK9zxIO6c8U3bGkY9/QQ/a9M/+xq7rrQBpK8wj73GAQGr6jN3r3ktcafTBQVISXr4iSqY5qoAJMrSeMPb/hHPvmByqM0o0QbWdoJrfVtccTk9ujJeZc3aIGiiNR5Hr99mMSkGAJ/Yw09+WP/1LnzwAQjamKs4dgdwwxyqTg9sqSDC8qbwLUfctvIBYDRRBJxtpIQAbg0oJr+o1cB3PKy3Psyfu4DnbOqVJ/H0RSyavbU/xhrHWOFQlQJCr67mxANAoEmZpRRv9CSYxz9hHbTiWudM54ddE9Y5nVnWVqdT2CTSLWzilTKMfWjNx7gzRx9RgV4XQyF+82H85w/wl+/WHQ+hGI5vyAwEMWgULSRHhBngEROeABcjdpMhSGyaAAWrRgKtIB1SGHg5rQjEhkDi9Hl/wyW97bI9Zxev2MSLdsA0TjmKOam9cfx2r0KNzXCUoUUJn4yUmPlE2chIx0hIydtL5E/nr2mJThHEFPuGUoOfzhuBjiTayoZ7tiYlSx+w5mdssR/1VfrQbiIUAsRd5/VDb9cb7+LpixjgJ+dQYfDzjYzpLegxBkoyQgINFt/RWG+EwEfZlg2JMFnCTwRk1uxSrF3i4Va4YTy4pF898F+Dvfg4vvgkn7mJ8F3qveMoNw42kCNDlbxRLhjdIfqGt8A3xR1kYpRKnoGOHrvMlKIwhS4Rqmh2HDpkfx5DRUJ6cBojRHLqJkpBvkZxXK49kB/jgwaJQjy8j//z3fjJ23Hfae0stDOjA1WEI7eG0AoqM2lipgiYOfLFU0bEnDsCj25HLFKANV8Eaz3FAImWgx/BKplpwyH628/pNw7K517DL97FidLdpY9044hXgDe9/KSLb5ShaWGBZ2ZSIKBpvBPNQ+4ijNMXmSBRSTBaKuYASWYWqEm4bcQDUC5SECx7RjwIXZBB1VXVN2iMjsEA4Gduxw+8A+9/wOfEiU2K8ICLSsvqdqHE+1aRihUHq+gR7ioDaQTdCBZazoHh8yoINEpOkgYjLIcRz92VgNEQTYokzLRh1NJ/6Tzff8Avu4afPQhkHz2OODgqhQiVaKhYSt2UUfNKAjrbMtK8zy0MAqdE6eYumC8Yr81vIwwA3RVe5xMyAnlEM1EJbWSniixqjcLQ9p7HKggqCBgMd53xf/Zmvu52mHx3DhCrGkhE+h7l2ZqEQ4UwMbl7lMQSo0SaOxrZnKBlmfZt7ccgI00BgoTUEAaANCZ6TUboXp6+nLQBttS9K/3bkR8+bn9sC8esry1Ht3Gg5Osqc+kBMSzOW8oaatw+lNEHMS7QGU86ix1DCaMy2eoiplcpnYhnnygUiEaFfzFMcogOi7T6iKANvqgVmw/DYm5THvVjbexwJZvrdb+B/+8b/c6HeM02QVS093QVS2x8AEljmB+wbYxyWN6mBEMMEI2bKwpWCMFosdHQQEtThGwNTb+cYAdkZLFI+IyLmMVLoRoHAvt6o/xu55/exJMGOjvd42iCo2z2ohImTw2PbIJ0IsdE9HKQTgp1HQ3dOOnpWZyULeVTSWK++h3gWLWsYwS4QGSxmZkZhsGZjmKstbpXlzTOLh8UzAtIm773jxniUXUUw37F9/yC/9h7uDnYtTtxDI+3NKnsEZxaaubXMPtCHEWYwDMJ0kErRlGG2EqUYRQEo0sFRBIbp0FBLSWEw16Ogmg5LgKwlCARMGyscMcZ/6fb9qeP46Uz+WPejOkoThyCPBhcedhXHlqZtAulks3XVuXrc2rAF56PFTa30YTcCumw5ajVSqOPmzMc3yrX7gzXH5/deHJ2Yqcc316c3C6LuS0WKAYIddT+vo+jVlWX5Gf3y9OP2/Je14Bh02w7iEtty8KRReGCo/EbD/o/+kW+5SM4tiESY6XZBHVCZGOXp9C4Bfeq3UAAS1M1WIwl8WGRhEFhKB+fZgTFuOZSoOKqQrSjbWltCZCtTesVdvScdlK6YYPY26v/nnbxOL9g9liHS4+WOjbQLoMb250VVZrS5JF8c3cxlo9JNjtd+xueJk5sTyiQ+FX1i/sy2qljw203LZ566+K26+Y3H5+d3CxbQxmGII0G+iEX5WhUMxpQ5ipbmM0xjlz+lGwgFljOfHEryi2wG8mNQ7rOIzSGNP64/usd/F9+Gg9d0rFNjABj1QgXFNJMa7+BEqeUgBxCXigHSiZuBjgBirQ4lJi1dYYGGkmRGQxOcxpp0RMyKgvmRgNAC9pvvoIKgVg8G+QBi1UUM5of6D+ew/lt/omF9BgODz96EwdDz1YDHM2DSdpthOwkAdT0Fo7uQXgYhabrDlvuayHlvLwavfoN185e8fidFz5l+xm3bpw6PivE6kDjUqtRF/c8V2NMr/aYfS0zV0w8AJekwQYOAN1RK0b6x6zscHYSdjOGW+EnnCeMAzSdH6/mR1uo1Aj88Nvwv71BS9fuHKsa72fGfcSasqehoY9I5mYeVIlDIvrElylCVJy/26/NCTGPbCRhTLQk5glOtL1EU2ORUYwsOc2kfVtDaEVgFEjaUq+t2juGr97AYxbvOHqyeri8tnTYmDKqFHn1zZo84TG1ppGDbHoEJiA6GCpwfl+LGZ9/29ZLn7b7WbdtX7c7EFit/MK5sRn80CAUGGD5AIs/ixsZK3SidNGSnFpqBIwSOGzW0VSrDk5zfpblQywD7WbhVgxPAI5f3ThIQKGrin/+y/j+X8UA31zY6BPOzGBSNAQDsiacz2OH1uBGyV2SJd/fRkdDRkUzAnQriXqKMOa2034QjfTP9s0kLKFTpCN9bDcBfBjJgL6cQgXNUCEnN0f/mUuYF/vKeSYFszeOq3hVaW+xdY6B6KrTShvRiw3ImJx4mKLajJtmMQi4cNkXG+WVn7XzBS849vQbFjPw8n49d74SmA1BBwgaI9NcUPIx15LAUTVJHlqkEzIfEmbp8qMxxnJg0Mq1WqIIeD8Xt5e6Rd3iG883XC/OJubT1bShRNf47jfgP75dW+Y01nQoUXTUJMCkzaLDmdfOtYVJfLsAqRiDY95so2l0BCCa6EcMItE0gAZNxcNAQEmZodrZ9ZBfGGUgIMsJxw1of1g4SWJMNzh343ypn7igjS182UbeWXrjuNonjuwdHgNwlSxnC3EaUMOmJ/9naN6DhlgMFw98KPjsZ+z+kReffMatC6862PPLDgpDAXOGyb4QL/R85YKqmKxFCWZYU7SNNbVUqvHypdNK/ArPpOoqWMGBKs7SHuLBx3y4gXw2+ATYFq6W9hEHlItLfNdP47+8T5uDC/AKmqMwj6MpAaKlVSPzPWsGi/uVpS5IYFA/aTS3vMHEiYvMXaP1kBxDcrhg/GLIOA0X6YfQpC4EYbS4soswuCxP7vGvay5NAiATiEJujfrxfZ4oeOUMlSi9cVzVQ4dL7u6QU1D19AnkZNvF5HMk6zxToolZYR1xcTU+7ZbNP/aia571+E1KDz88mnGwJGrIGaIXCMVIyEdZbMbNaFS1TcLtopdGgnnnQ3PuOKTKykeZ4qnnjIldPq/LPfrHbLi38BTwHPDp4CJ+8ZXbPkKxdmmpb/tx/NcPaXehZTidABBZCWtC4saoobX3aLthAUICn+nk47mjNEPX4HGwuczHupnsjEBDSabaPq6w6WHPluqZy1GYMKmAbiKbPwsbFsbpLJ+vM2s/yrKsr53PHjfwiY8xScuRdDlni5XOmbdtoTxEBm1YnIJ+rpkN+wd1e6t8xctv+Lyn7w7ExYuCYTaAkicnA2VKYktxbTSCSbxCrn2+8hIQK4vFiyqeqzChJrznclkcFNqkIhidYoS7GFbFR7k9yPkvFX3AFy8e8Hhonh7qV1r7CFzj4h6++Ufxhg/pxBYO2rN7LQvO+wfadwpNQghM5+kmastRLVQr67VAyOli2mzCeC2nmELwEEcjBADJLWUQNtjQEJEJuYRSTpMouu0yrZMhEbE81WsQH7pUv78Mf3Om3fIYAjuOosu5q8qDct5U1u3wmiTxpGeAFN1Ekef2l8+7befVr7z+lu35pcv1ADBDIeroocNmeojmrTZCY9mgkkNPyUya9mbE0UjOqfKUZABporwGN7J6giXyCkvWIqf5JN8/RUut+ICVN3i5zvgS6nFgnBDtyunaIHV5yb/zWrz+vTq5o9UYGGQDHbODZCpNDFmC4gia7PH4XqA5yMfhAxOMPS0QKX8zCkEpl0gxNEQApMCSENfZaC+l/bakrPWEfLJoIpnlDX89AbWWEfBMu+GsjBvCBy/UH97CX9gsubf2xnFVThyuw7iHDrn0KUfaFrYmGDkKK1/90c85+aUvut4qzl5czUoxcziqx5DbbG2t2XVQmTdLGEyunCjYjnjT3hIzbs69zUuG4UFGUWb05iW4FuZPFKV4iDXyvBncsL8/lo9xuL/YU2kvBk9eKbhpjmLO7/oZ/NR7dHITo7djpjy5mzZNFhma2dwKZCJLO4JO77+2kiSvJiaIKeuAcXC1TPpmfGa6+yQobQGXgjRYgKiKVsS1WfV066XWuGkEXiRehXwwsGGm+TNeSvPqv6byYuCFSFOn3jiuJmw0/WxDFOtUWyE8ORvNVzhhUczI/ZXPF/jaP3DTZz/p2MWLI8yGgZC8NhG35wOQkqpII+WV05d2OFv6kjFkli4jfCIgxa5jiIsKEeTGeDh5dTNzuQWeb9FpbOK7B4daVVasukin2Whe9zW8h7yTs5cWPgMcPvNrSyyC3/fz/A9vxrGFL51GWGGwObMjZpyEM21KlGtI3F8dbjSb7J3Xb9vcNgJpymGFIUKJr55pCXlPkSALKmrbYkSVBoiE02CC4/EwafSbkmBKfNm4tkBxrZ0W3NQXwIPxDu1d9h8deNtgJwY8FupIoTkT7zDYEkoTjDYXi2zuC6QGw+VV3dnl13/hLS+4dffM+epOCC6rjkxGCN/RKnkQQVAl95SgAB4PwTSlAh2s8nTtAQXmV4q1XUlmTaVMimXMBcrS88NVK71KE3utCpVwauUaiQpfSktAWFHjOa1e7/pZ+tk10e0zUmOFEf/xrfy3b9DOLDLw0i9+2uHSEyXmMgMt3r1I7yQF56JhqDw0I+bsEbHdmtAKtoHFGjfDTJa/Q8CgUBxUkJ06tIlsiJQZgnLacOrktsPEBEosOX1BvGGAMARRg/RncLIIH7zgP3sQ3a9PHFdlM4wkhLjdN1Z5TqACoIphKHvLeuM1w2s+/5brN4eHL46zmUnwOs3QmeYWy7l7e8UFlBort+iTSUSD78I1yAEzehyCaUGXbkt6C3aa/MI87zsKm5D4hZONROM1xgASMpx86ppkGIv7HVqcLXqh9EyYfQZGj+oYCl736/69/4WLQSrypltTE5jlH8rdky0eG92kFsl3Za6QliKRFn2TSGfcTfObnjdZIVw5SvJxPJmiuSHGbWUdawMC7nEUY1tkbUI87RC47Q2YRYqpJ9yKzdcJSUMBtCX9cvWXjbhtZkf+wnJ0GgcPTRzeIpQ0uXXlURQSBrNL+/XW6xd//lU3HZuVCwd1KKYMSYjHRaIQJD21sJnXxunVHfL5RoeWjIHM0dJzzNOOKtwjpjYRl+GYQFraG6fkN+UdEO4oppya6EF1QNN+TSFREV/rBfsPjbNfnNnHTa9w7pj8kHbu0e8axfDrd+k7foyrlc83MDobzqCJBhoUi0YJZaNxx/DRtITrf1gTzOMim8xOYqLs5VyiYH82NDldOabbb2OTsyEhQALRbO/9+EGxOUynHzWTW4Npccyf2eTUYqaEsgwAZ65L1C+ST0xySV9VrsKdJSOW2Dw58k2rwWxv9Guvmb/m82/aGsrFZR1KPoxcqFW1qtZIUWlEMjCk+mFDqIx4y70D6Qc2eZfGTNCcx/JwyzD/UDrarcPilEZkbUpOcR4huqMZplKxrbT2qGmqjgvuSAlLH1cfcv8J1Huc9mlaW6JrPPCw/s6P4vy+FnOsxvaAbxZHbLfwycDo8Lu0vXenPMdsuPkubT47+fXawXoNnObgkXxSkChq2OYh0Lk5y7etEa2/cDLvwdSMJi+P/NkyWSdrEY1oOZzmJgPQWPbru5b6TR391Bw7ag0jYTAKjCwVwR1SlSSjLUdubfBrP++GY0O5fCCj1Qp3Vo8YJ1TR1T5S8y1dXe6qYnWvtTmVhng/f6PJ+Jxy1omE7qiZt9B8xiYXUzUYJfqOILb+0n4tp3NkNEIPcCT9ieBUhSpV3R10VRtXn6j+ExrfXcFH/fUbRK/ze/jbP8L33+Ubg5Y1F4mmLFMLr5KaSj3ceqLhso1NmqzYWktMAZtFp52Sw9uJo52SCg83aQRMFSNGprOQay96ToDreltMPljo7tF4G2xS/UOTa7b9lvyCdsJt0X8qxEN79Y0OPwy69cZxlSwtpiaKzResSxQtwI/66pffeMPm/MK+0+A5DkSOrKG5c1RX9fy4O/Nlpfb5HpZizRkdEOg+5c7mTqPWBUImkyampDyZT1pfHdtyD7ZBIUOhIhUKEwzbYI7cqRwaoUqO8FE48KpxvDzi5+Fvkuqj2DtilHPX3/8x/ew7fHeO5Wr9Jl4LdRofI/NPsDaMb/+FQ+fo7L6WprB0tfSKzLWZflG+4XPFpDXIMjmoSHNAef7mWt94Q87fNlifJLgwWRPaRuuI3mCpYdEUvZCf0ZYpBptdIzED3npZd6ycvXFcXVNHSmPTKNA8oUIj7cJB/cMvPPn0G7bOXh5pdJe7V5dHomw2grilTGlLmXdfU25Lj1zrtm60xUEuerDSg3jm7lNCpLcASuTj1NecSfoEw2uigRxqImpMDrYjJPIEnJcKd0gagRVViRFOXw6r+g7HLwB7j1bapAvF9K9+nj/833DqmEZnWD8n1R4AvdE2c/eYbJ4BZLhjQ43Xira2vjWCaUvfzXd7y+N1TYQPTYBHfpcsl0U0t8jWvifHDjNau9xYWi5MjtTAmms+oWRsTLL88/v0mWwaa1r8qc5Dbw0wqzeOq2NNiR99PJBpVawuwJwsKBcv43lPOvbyp508d9lLKS65q3oeU2uODKqwSOsRWCtzVQHjTeGCN8Zibebp0VAiVsGdoEJ8HaFwMsvJmCanJqW4IKa7aWS+xHsk3hf5wBO9/UO+WchoXmE6gopw9pDkVao+uZ6NvqofqP7TrgvNo+ZTC20QP/du/uOf1rFNjTVaG0L14bmJMV3WUlo23U+au7MaS6WhwDFbsLm1pnSlbRyeWhIofQNN+SOfmtIUY9Mw0kxCCIvBptO3dfBFgiONE0jALG2P016IopzBUm9Kf6UOJm7/attW+NTSVv4rS53xZinWG8dV0kEyUoPNvtxg+yu79lj50hdee3CQzwnXhFBmrperAZaa+oJiPVnDnI94dlu6fiRYMRGV0KC/KdC0hUBZm1CAdsFJb5lpjW6z+/TAihXJhYxsyFNxMKFaO8EaHJm2CK1s5fe4Xud6uMLWKPEnWaOjGN57l/7uD4HuZhlYl3+MNi9NW5im0WASpgjUI39iDbsE21+tYY/tQBK4MQ+b9jWRy/oALTbsuaGyefmYUBlO+Ebjl7RfrPX7/DAW0h5LWi+Rv+Xi3aQtgIjiugB8YL169cZxZZ9j2wjtFXJ3n+4fwqj6h190zfZ8OFgJ4Ci4wwPFcI4VVT4K1enuLo4eHSG7ibtcFop596bcRyIjiZI4XJRnXEt77camwzRAFR0xorDxrtdcSM/LZA7Uh16ZafKh0GNMj7g47lQEcSV7lee2Fj1vtFV9wP0n5fc5jJ/83OHCYPjEeX37D/uZ876xYPWWW+BNLZKSwMZXEZOK17aQCe0JAU9eVSYBIdLspIHGE2tsfctVZq5kXCwbDKpsSspFUnHrbdgK1gNOYrVk+4am1t8TeNYau21qoaaKzPY9LTVqII7kgBbGywf1Q1j7lfXGcYVfVHKYqJnzGKYMduFgfN6Ttp924/bFyw7jGE0FGNv2EaeXMDWO2woSFo21PcaTaBMT7iA9IkE2oiAzuGU6Eng4dkzPrsm2o0lqfPoQgDjotK1CEwdxeqQG3lFzbcGEvrqHdqaN+7FBQQ6t6uir8aERr5MeUHDYPpkzCoDViP/1P+Gdd3B3G8tRJltL22PckybqHSYrI1hyYZpQOb5pTGziECNumlvacz6TtSat7OEkvPa75qyhQz5Oiao2sVzOE7Fy0Kc5JYUnhxzWpEMmP/J1hPB64pn8f/J8lA4gNMCpBfHBUQ9UHVWI9CiuKo1uGPD9coWd7dkrnnFyf+nO7AIOugOKtARVSmCN0ylZlffTClShSk6E3jbfqjB5bPWJjKRvUHQEb/oprVmheXlpyekZCRU62sAsUlLDIKEHdOIJzebH1SYRb4HKjTQSYgtDGkcgglxYoUqsXFZXn1j669zvczRrw99H14jIqu/7cX/tm3R8W6tVO3VMM0RefyYKVzrMB/zQLhWTJ3mbTvJo6pP9xaFeegjsSD+mBEAb7sB2/42uME0vjWxmypGnZSVMuDJoObflqTvBVJ/M4iZjUwb7DikoSDPkeB7E8COzVNm5aU7eu+cfXFbgaDLQj2Dj4PS0qiDsYNRLn3785FZZji7C3atQPUlZLo6ejI+q0I9QsDqJWfPoiJqvm3j1t3BJ94akAu0hJqLp+hN5SP294knMfF8HLmHxqmadDjpNtuHEuv+01/Q6AHvKKcLEXm2/3ilRIzVKVarAyjmo3n+g17nf8/u80QZr4z+/lf/yZ3hsS6sR7gBkkrdEksMogCZqLSa6ZVO5ceKbp7EWs23mMJKc8QmJCHJ4doWJhpugTVsTciqYAjZDiZZLTWrV2s2q4VF58aE0RYI2fMNzr0nTpLU6Zn1QS320J/UXjaEa8KpuD4JpbxxXBcah5tNkxmW1G0/Onve4nUv7Alld1eFglao0AlWsytdt0IwccqCCFW1taWBnvEYDp/DpsppxCk16FXNH9oU4l7TdhljzHtfqCceUMMvJMLVN0Ekzne6V9KYFRxtb0oUv4rRzIxerB9hDZ7sSV800PrTU66vfN/5e7yzVYYZ336n/+fuDSRu6nukWkavCRPiMW7it79WN4cHJIDBuX5zmhCSB5oqWm8z042zfXU00CqQXfc4vkyLFke/5BongEHia355GosH0A5zgWzS2GSdd3bSmTR4hUyh5QiyTcXWGfVZpZrzL7PwR3VaO4qqSUJxLthr9BU/amRdbjV5d7qxgrfLGEK1yl2pVhSoUxxT3oHXASfcAEAJtpER5kBWYXM9ULsTz3oPNIOSxNu6S3lxNPTnpk3Q0+ewthL3xrW3yismTn0s1HqDtyar2ngptnvJ0aKpSTUyX8fcZ4TVI645S65kVXjfqE2MQGH73s8b9D+Nv/ms8dE4bc3gFYJqidxPYAJoXK7EmSqRCtjE4U6zcDkZsrLsGBNFazGssc2Fq0Fjlh5JWbH15ys5MhBuoZbRKS/dkElLjYuMTijtBSwiK8CMsN9ZDUgOZ2kKTf8WwCInXQTL10Ki9BKWPu3/iUD/qjeMKLw8Y4WBcXnMcT7tpe2+/xhGxqgEHgXp6XkkqWF1KWlfMAGw0pLahBI6hNWifvaONO95e2DJMNsjtRTPpqzIoTk0qnk4y08OKwZeeXtLtrpl/kvAGY/pwpsS7PWwD049TtHM6cGbkg8cmJpVaH6r+U6PO+u9m7ogvsxzxXT+iD92Fa49x1MSeOHT5nJSt60ht+mEQE2m95pO8rN1IhEfm6LIxxtYxCZPpztROOdmdxJfKa4wBJa1UONnQH/q75Heckwh2upw3KUDDvn39DUQDU9dNxA9lYjdQNv+YCVVJS+De6TzUG8eVe1WJt6a5q4Ja1vGZt+7My7CsqpHqVlVdwRl3R3WN7o64trbhwqWEJ5BLb3uaOMyZcKdLbkp8FJkYmZfH8JAxpNNDIU0+GWRZPNxc1jgilv65NMLoFkjepM606RMmQki8cGM3T0zjENcgEy/jIKRprYIqfARGB10Pul7nuqzfce6oFaT+2X/Bj78Fx3dUXdSk7FozJVyigynjjfOUM3BdBAdOh1TqxMSAzbejpW9os6MnIx0y+C8NJ9Fad9bcVhKMNa6pX8UyNTYtP8xtWpG4tm1pORYRaz+tU/mDicFTgBy14eJQjo2cUkQz6ho0s+zkkV1OEHcdUSLHEcQ4CCNLFXa25k+56diySiWYWt6on6qNMuzJdISjscjjwR54hzAJxPPh2lSumkaI9vBsv7ZxBRL7WKdyONZExjgUZqyc1geT9KDgIVFmyLZbahFpfkiuoZTuT2qMGEgsSO6NRZqtDu50YISPXodlvWvlP7fyVcX//2G6VgwFr32zf99rtTv3Wifd+1q1SrS/9nRl9oxUy3FizQdruW0ThqFmPjqlogTuyzXz2xvXyyb9XJtqQlBvpBVwyLh5d6nCa2oWNcau6E1N3Ix41n+TaOhqTLx2IbIY1tYZXpLqFC/cTIJwOOYrTzA2GSI+EF5yR65xHMF4BLKWgoMVnnnrzsmt2cFqLAY5qix3bYMh9V/IUDHms6OARHG4yUARJngA8rCwr/Pw3sCU9GOxTuchz8LExcOG2MN3LHIKG129JKUabbDN1JDA1QpIo7uLNJhKG6kjoVDp4ZEGQVBjjeXCEgSPFiPASSfjTauRV1Chzvbtrk28yfRKsfw29j/VUYrecwe+4wfNUmQcVIV0Skyn8khphuSsJgtOVyAeRjaTxHQ4iefzxP8yFJoiW6VJaYMUPuUhWUueBsy4psWQxtLIn4otjDaozGwoGAbYkHkrZunE465aoTFiaNtpipMETuvoN2Q6VE18Kj2HiEm2SLW/Zv54plxspTRuHOt5K/uOjYIjZoB+pDxH2z9QsGL21Bt2arxEgj4R2CJEp8OQZ9AkW7a9FIA5Ya5qMqe390mlTCxFEKOt5NYelCtjLBZKwTVDVcvMNVYGHDejSmZiGCRP7/P21E3QriTjMagTBGXNjs+spT6kfZWjWqa0pqF/0g2mQDQmeqhsgh4cBsdl+8AWtxyfM8Mj88gCED13Cd/yf+DeM37NMY6jSIROxgbKPeEDtYBuizDoGNosibeWhu90oSQ6StMUjtLeriLokpXmRmqtG+ebn1ZEM8bltq0KmNt8A8OCAHzUeFmXLx6Me8vlXvWle5UNWGyXja1hvjtsHLfZbhk2jAPp8KVjFBw2C5HN1AjiYYK1d1CccLzJfTO+0psgH21ZW5PgJRTj/mAXiI0+cVz5DYSOgxVu2V1cd3yxv3QOXCUXmxOLkJkDnW8hZgJYOkfUeOUo359ai75RpYg9n7jUsBYvZJNL3fpLAfLIQ7UYTtbkp3YjpImgqrwYnHbYMqZCKQlFeypzMicLb4i4SRoQJ51MLgsaWJXIiB/Iw4IEVSWcsAIF12X+ykybzucu2BIYE31xfeu/w9s+rGt3NFaVBsEmyaFZhbS+lHQMJ8wJOEv7/EkzL7fUoQVXap0K3m6uzZonvBCsYapFLBFDH1GRArGxZcNc9UAX7l49dNfeubv3Lz643Hv4YHVprAe1jvA65neZsjIMA2db2DzB3Ztm1z5p86Zn7l731O2da2YQLl/2cQUN7eK6joEJ9gdq68vrBHPmRqOcVyebOU4IigmXhP2jeIE4gmn1oI/j+LhTO/PBLu/74Jo8n6zp2K35bFOokImRuhas6RIQZkJcMIcX5ICA9hSKWdXCZhgwlZIdBMYpaD5hADtEP6SRMDNRuZxkctg6+FyHzhNw92RX5r2zbQht7Yl/n+kAeRKw9uBjs5lJWrc8xX/uIFsTWeFNpmtquXWIlBYXiuEf/7h+7C24dhfVjZIsEmGaUacIOTyuwNPZVZb5rhlPF73A0yJ4fcFIClj8yV0yQmEq3CLW2Dia1q5SoiqwwHxuGP3hOw8e+PDewx/Zu3j/cnVpSVSa2yCStkBZgDJfC1dXcCwvaP9MPX37+JE3atgcdm/YvPnZu0/+vJO3vPDY4li5dMnHpWzQEEutTdT13FrzzhKwknsCudVR8jzkkxsABFqhluT5RzJJeuO44vCNVBYIRt54crF0VZv4BSTkYmHTrofNaIIH8sQw0oVBPqXP57u0saYRqaKFYDEWr4Kl7lqFzK1bYNptQ8Pa1TYWJFizwY2Zx2WgFWTiB9NyN/FWs7XNcXgVOiYGQxxw1s9JyaXSlOJrVW9TrlpQOoOCYk5BJs5olw/whoI/Rpwo44hhwOvfrn/+kzixmfTQZp6XmG/uScKheLyJHZXc+/WBtgGfa5PzJGSy+Siuf+XEGV1fT4n4MZYZZxu4fKHe+869Bz9wcOHesS5rKbKCjV1CrJOMLpi2odbJYFoAsgIbOLBQ8Irz910687FL7/+5T5x68uYz/vCp21517eZN89XF0ZeweZJLPHHwZhsdX9EAWnxts4mkpubPpOkufwBdOopKtyM1ccRQPLp2NnjNsfmyipIznxTW5ot4epunl5PRPPzFLbE0h1lSLeSwgZPNQz5HlcKFdModis1mNluwzEASdTrrhnSWK4mSESyIALH1jN6CZH3KKnLJ1oQGHZaOxyPPmiCFmbGcyzc0Tfu+dtTy6S1rE29BMRpQ5pQ0ygeVBw/wBvmXbgwb/I279Df/JVYrzWaxDHFaMBJ2kGBN75pXELW0XAU+PNE00PjlHvhPcmLy52GFa24o1hoTuViyXZphe5fj5fqxt+zd8+sHlx+qLJxtDLMNqI51zMMzRQ+ii4UEP7xXo1vWJkxs6ycxbGC+bag4+9GLb/on5379R+971pdd9+yvuGHzmvnl81VpKs3JsKdFH0iOaPqZtyE15DnX5Yy9BpbCQRUG9sZxpdeI8dTx+ca8XNqD5Uktt0/LjANlwDMn9wwjVFtCINqerUPkcUKjOx1D4WJjWGyizDB63Vutzh6sDi6tKlwGd7JiIDcXw7Hd2c7mbHMDgwaNGpd1dGHQMFieggEUok4pYWrJYmKcc0qzx2rKNUv7n1j/J7ZmIC4eE/5kZ0HTlGWYK0uwzIIVJc/fOtwSh33cCXuH7nv2/Ou+r9z3ME7sYhzz6ovSGnMDXVr0ZPszCPCcodrWletZ3EBq/MuEqBPkyTaXUW2WduQTlUNieE47f+NX6+1v3VueGbd2ubk7m5kOliEsIc3CnCcx4fhGGuVGOh2eKn1vrHVrfmSsK4EaNjHfKvtn9972b+6+/ecfetlfevxT/9A1l/Z8f79iwGQYKII+BfplIHY6GAUP3TClRsZhZbWq+0YM1hvHFU7koMOvO7EBWo23RV5OZYS7CiK1MaPEQMucFKbhnU8pgFCJY4nB3QdpMRtmMx74+PHL5+655+J9Zy7d+/CFM+f3D5Y6WFX3tdtEARezsrs5P7Y9v/74cOv1Wzed2r755PHrrpttzLFauhVxbvKWnFDQUqREg0dPMU9szpK5WNYGpzHqh/ATEkrjWmWGGZ2J4hiUTA3R0cTtaT1msIo4MLOg2qp8YPW//yredOfmbVt1f4xHNxoAk/SLCS1Omy8AhS1AYr1+oD2KnbD4zg6JOcSfeupxkxAuSHAJ5RhWFaPh+BKb99fnq7zkD+yeu4g77vF7zi33LtfN2TgSIyL4Licc2mTo6CTIAnNWdzSyKJsDfGROhA9g7B9zDpvl4gP7P/v3bv/Yfzv5sr/yxI1Ti0vnxlIaY12kYYKU0u/U8huitrWxBILNQ8HkfVW5gu+x4eFLs5PHNkZPsRTbQ6Ht10FWjHtic6jLI2Ebu5PeSBlW8jlsa7O4/KNnHn7vx+//yH3nHjh36fL+Cs5SbGYcyqxEqmDcYhkUAV665BfO7999l78T5+vBzj/4/x1/7p/gxTt58S5eug+XztTFIhahNAWXA5Vx44vM97D4lqSSHh4NSF0fKSbyewKPlp6FCC7mJB2LPcIjo9WnwJkkhji4Ms6qlv7q4cJPXjvcfbFsGKvLMgN6sukTm/4uTjwW3PKCAIZUwMkgWPkbZ09zshziTQSuZJO1eNK7Ayk6P2pj0776OXz5Kd28adecAIG9A529aO/+2MYPvX71C28b9i9e2phzJYMVNYJ+GBxnb2hGgybCLY7JqZ2zsM6Au8wSvHHXsIkZ7EOvP/PA+y+98pufcuplxy6dGa05OoZnsbfQ8vzGNskbJ7q5YYpe8COpQT8yrogtgaB+yzecP/jQ1o03zveX1Ro3MQ+m7WdtZElNZk6hhSpgKcH7kxkkDSw727bC+L6PP/C2O+76zfvPrFa+KGU2lCHm6sTyrN3jZBwMheBgw0AzoQz14ln8ub/+9L/8D05OPe7c3XjoQ9q/h+P5utjgiGpGVvlIVqGCMgrF0jjIHHBZwrPpy2lppt4OFXJTHCOUKSxyS/Vmit5iIjKLfbyCJD30HTDYDF4wHFu97qGd/9e7jy/y9kojLRwqml0vSjsQZRhS9BHQaAWKCKWSV2cWmAGGWCloMAMLWFoSfQEHmbEUDAPKDOdH3Hod/9oL+Iqb1z9fT8ltfuD/+mV+67/Yf/D0pa2N/dXYeGCq8ko43CGP4D3VECqHVjEaVNhRe+I08UawdqsihzmXe65aXvoNT3jWV1538VyNPhfXe9dkbQrAp+UFBlow5dNu5ALw9cPsixY8YtluRwrjIDBW35ob5jbK01wngDbQ2JhIydFs53qXtRdE2mCDPmp7Y8bi7/jYx3/pQx+58/TDhdyazbY2izsgH10WBA2ZZRRkPOwDFSmBjpSCSxfKSz7vhtd8yzFPYhRAHH88jj+eB+dx7iN27iNaXLLVMnPVFRoNz4E97H5jaYnTj006UwEGd5YmrGOLh2sEqxasmGLPnMBiImjXUUpibDMrL+TqwuyLr7/8V588+57bt0/NvDpwONXAJZO1PaMN+7KEj6Z3IuETmzWuQZoGu/xQvPNsvd4QKKYLlZ/zRPvbn4PrN1F9vcYUHuog5Fd+Lp71hI2v/a7Z+37jwrGdgzoKqlBpAAMbkNQY/WgU1kY6ySEOPln/5MuIGFc+2zA53vR9H7n04PKFX3fL3t7YvsWHLdnUBtS85TfXlSDgmODDrF9VrvjO4cL2YrE/2KrGa8YlFMIUhCJCbmCJXNAct9cCzrzPAztbw51nHv6FX//QHfc/aGa7i7mFtr02EWZCfzwkrQJTUmLG+M8g187u4hu+48at3eJVViYZOAgsjuH65/PE03HpTnvog9p/yMuQsGgEw8k97sacTHBE1YTwa+J0cTJUk4x687ZoF6SwHCPMG1YxxUC3C7DkrASgUUaMF/nXbzv3Kw8v3vKJ+clZrYdRpCaVD0qo5ZfI0S6tURubn4f+suuLOYMd3hiZk9DWAOnMkn/yufY3Xqx5YRXKb3lMs3WQ1YhnPwE/9L+UV/+93Tvu1vbGalyJiptYSuIDU7bSftrrw3S+1w0ALei5jTmTK0cVWLB93exdP3zvat9f8j/dunfRIaBIse+iqZzjigRMHuiK6+1kRHTkyo7YxEHasc2Zi9VVY0QNY1EonTJIZ5j3qIq1GZSHW1d1zWaDLfgL7//wv/vFX/3NB05vb8w25yXiV6AY1ae4g7D7i6cbjYW0wmIowRabz+zy3vDHX3Pts14yd8fUNXBYXOWYb/LkM3DrH8Q1z+PiWHGD5sJcmgFzskgmFYlOoxdigApklNEDtbEpoLWxTujN9JeJR3oDb9YJlNlvmNdbwaXqVquP2BzH73zm2WNzLT3shNXIGs3AxmHrQJhmAeygmkGzUtjBvK1kp4B7ExEnvEOqGOm6CLzmxfa3PhszYxXK/+NbbjZgNeLpt+L7/3a5/tSWnKUYzcTJjcNoZAkCu7GAZgxKu+WOyWKkWSGsTElO+W63NJrduaG876cefOe/um/nWMm/aPDdo1No4uTFyTnZQBl8LtSqo6esP1LqWAmF3Nng6PL00YhIlGark0+DNInyjF6N975V1+a8nDm49ENvfusvvu9DQ8HWYuYexj1hCbfOCjOCKlOmaLz+CktBIQyu+WD7e/7051z3Z/7G9U2J8tv9oeMn4Ng4zptfwmtfoWueXNyImTgHBvkQRwNioAbQ5CX+Ioq0ehncJMSQzknuNj3jrUlPBZnZdJFsFjmBKfvEYJJzVuvycnnuxsVvfcrDl1HmNtnsMLhUQSFLzlbzLcfk+Z2oqyYX0kbOIB+piDFTiXOqdHbkn3+RfcML8t+X38WDejagVrzgyfg7f3a29O1hGEJRj0IUYyEHgxlLiRHQBoKFVlL/U2hGRL8xohiHwugpA81oxQj3qp3rhve99v73/vv7No8PdWw6pdQlZ8q9mkHIdFZPi6A8kvXGcQU3DzOycKx56ExGl8L3CR4psMhYyBhfXRyh0X1jMbz/gQd+4Bd/5a4HzuxuLOjuGgGZW2nNhZNjjGikmQV4aHEDAQEOhpmRql4XX/SVx05cG/Tu3+nnIEA8frNd/3I79XwrGyYQBSiugSiSCfT05jCgUCZay73m2sO7CTSbmBxhMZEU7Ix0cU2id6RVeBgJQSM0olSNl+zP33z+y268fLbarI1srnwftBBua2wuZih3Mz8MFzVMsZhpJZosNnKd1ViIC7K//DL7uhcFfoHffdi7Garjz7wKX/g5i4sH89nMWMyKZcoSaQPLYCwRDFVgRBnMjLOBJTT5YXRAWjEjh0SoUIwWTwe6tHlieOcP3XvnGx7ePDGMY6gcp5QY+TqdApOfqa+DFXrjuMJ5HIQBtcrh6alBuJmDEf4cN9qawQhyxpyJjc3hHXd/7Mff/LbVcrk5n41em3muhVDSJhsK0lgsKeU5EyPtIeJpZaUUjeWGW7Ze/kUz/C7jNdryUua44Xl2/cts41ozMxltIAZwIIoprykhDGHch9LsG+lsikZaS6vSSGLNdDQ2rSlis2g2hI037TQXq8xdYnH97aeeuWbD9yssXXMa0bPx6Ca2e+a6pj1JEO5dmjxBI/AxGGQtehsw6oLwF17Kr38xqn7PmED8fTYW9s2vthuuW7gVC1zElLcbmkiWwlJYrMQkUowkSkEpLAVDYTEE+kWDReuBjCiFJZASDZt8y7/++MWPHGxtD21LzQt1WkfGMBumA+k7IJK9cVwNDSS0jOlwbzWzYBlZBwFweILzlDC6b20Ov/aR3/zZt71nNthQONZV8+mPRhAIvNlk1C8SZUA8j8yat4xJhaRsZsNyb/6cl2ze9vSZWoDb7779yXH8cbzp87HzBJLmJhRiAEogvbFP5AYQFiNqfkNr1VyEyDUHviaLy4MDD5s7T/ZcIecN965RpfpqxaduHPz12x6+AJtNQS4eR+sWaLI2X8vRgtMApLU9sxo5O4gdBaEV8ocP8NXPt7/yoqSu/D7eZIWojs95Br78D8yX3CiDUMRBLIBB0SasWCFLoCnxOxlzo7FcMYvFNMcSY2SJx4KbwSB3W7Du17f+q7tLdRs4db9242oxwAz32dT+Hck6Wo0jTwiQhVoE1eVEDheiE97c/Zx0aFV9YzF750fu+qV3f2BrMS9mgsIuJjEyxjZCWraImG7N2E4naUCBppo1I2GL+carvnyLliyk31vvM0iY7/DUS3H8OWaDsThi7kiOADUFk1hjTCabLVZvSs6Jws1DRxlNIa6T3ZmCjepKQyNGfEPVUDVetj9708NfeNPe6VqG6SjBZl6DjLqdVgxN8ZSRL8Mc9ePe2ZS0ELQwXljxf3ghv+llqA5+EvrRmHX+9Odra4Eq2hA/r/YTMsYYEUAH458Gi20TZgiWm00HsRgYCMufdtgxyW3jxPDAh/Z+/bUPzI8Xn1IyMEmQMRGPs4UCpfSJ46rYWJhhaB6BRBURLYJ8AqiRp7RyzRfz999z9xvf9a6NYWDLMIBKabY7QLr0BJLIbCgM5pOlXXD7lyFmMx7s65Ynzl7yqi2kCeXv550AYZjzhpfg1OewbAygVKhCBc3L0gW8/Qy5PpTmAGFr8dnaijAzm+QtzyHMrloyXfqIhJNpFZfC6IuV/pcnnr5+w/dqUs2tmWyknr9pUH19f2wbyfR2alyHaBwz4uwKX/Cc8q2vRLFGxvvk9tTPeoJe/LT55eW85A9o+llli81VcjAbig3URGAzQyGMHMhSYglFaSAraUOuMxq1cWJ4/888fPoDe8N20cjJwHqKfZiWuWSwWm8cV0N5xK/FOTY3FDkYZG6ZOSmySovZcO/5M29417tmA8hMm50cti2eQQpD8SZeR4lJNgmQLCbkUy1sOQAjDpZ6xos2to8ZoN//+6F5xpx8Oq59OYbtEjAnAtc4FOwOi5SG5g+eAtmgPLVQVJA0nzJX24nUcvnSOoExIzCJCtVaVlju2zPnl7/p8Q9dqKUgdaxMR+TEQi2MUfNSOU3wLeo2YyCSIDYrPLfHlz7Zvv0PYV4O/eafzH5asTm3L30JDsbmQVoGWEGJn0JI4UouJoyJMU4wiXpgCLyDKIbB1DJfVECLuc9UaAO0HN/7Y/dGMF+7tgWuszYOy4U4BEK9cVzZm0oCBL5uHxHRBm9uLNUBwalhKHu+/KV3vceAocyqox0OzYIFKZvcqNqsUcxIxrMpjHVYSjHGo2qIjb/6araYP/cVOwC8fpJviNwIjj2ep17O2aapSTBlqfbV4fQg5F6VnogxHQCHwA4LwhI1jTXtqZjwXlNzKZEh1XFwrFb82ltOv/LaSxdrmVnO5xNhCmu6F8N+A4dTATTBMRI0AJcO9Nzb7O9/CY7NE9r4FIyaBgCf+xy75bphvwYUWkoZomWwQEVBeyfJCF8xIpaa6B1mDfKw8HPDYDSWmEfCDN1Y5Ytjdt97L973zvOLnQEed3CGgVN8r2NT8yPpU3wUJw4BShAUrDFwK+nOkb3kQo2M9Bnf+sHbz53fX5RNd074ZuM45v0kz64ohjjWGdsGXKwE99tYDFbIglKK1bEO8/HJz/rUGU0ScmzfgmtfhmGjuECL22LTx4fQtfnJpNA7nflS4nE4eVnGlqEdRiFtj2hLUqrmqzKQpVYssVH0bU8/sxiknHHYQnMZiRKa/L6b67tPTNWWnjKQlw508yn7zj+K63fon7pBvhASnnqLffazNy8urczC8c2i4SdnpsSFm7IGghZDAYwsVkowX/MZoUIzYynB1wlYGhaHHzMb7vj507OVBmv+sR4XaPpkjb72M+qN44q+pxAIjRgyh02oeUahK/gdGt2Hodz+8Xt/8877NudzSWaWe0eOnBERks+Ydk2MxSTRsxKvysbZDLAjPu51duOt29feOAL4VF3iQgq+8wS77pXc3Mx2Fc7gLVAgs6013UoCGCXNUsfa7MUS8oh3rIsI56AcrlqijNL3GKNxxExaXR5eeurCVz3p7NmxzOEuVc/kFsSSNnHNA4KNsaUmvduBQi5H7O7YP/xyPuHkp7JrtL80CvGS20YbhnZSEeO2WooVC8oGY7GMCXIwlhKIqQLxLrD8JYZCGhJXglSEwcLCYL4z/8Rvrh5834Xt3Zlq2EVpzVghQzMQkZC9cVwFQ8ckvJqiW/Po0XoHUM5d2n/XB39jGIB1/E8gdBl/nvY+TYqZUAEmODE/E0HdSE/dfG6xLh73xK1jJwd9ah83MXc8kcc+h7Mhp2Mw85xCwTbxu9DAGQAZfr2Oq2YjvGa6woSZTkGHaOGVqfhwwmWQj/zGJz/0hN3x/GiHo+LkzZy55cliolk3z60C1CrO8J1foefegrF+6kHD+B2f/xQ7eXIxOsxQCi3SmaZhMYR9AYiG8nfKjDTAgvQVvpDxoghpr9EQC0u2IaOVxe2/fF4uGceM6QlScrJjHBMztzeOK37siFVlBGrwm4hGeUzjWhvsfR/9yKVLl2YDhWqWs8NUoJk1hw1aScKQxYRqmE6xQTxMVVthPNvm8MWNty42Nicr8E/d380AYfvp3HkeBotspomikWkjmJLVmxVfXhgy1SQdL2StZ64FabRMbY/xrRHmmsNFgdel3bxY/pUnnL4wWrpzxYNW65Q5abLSaamNSmnQwcj/6Yv5uU9hdQzl0Rg5AeDJN9mJHR04WVpKW/w8S5xRyEKWggLLj8QKo2gWKtZWUjNjQB5lIEuZWo8ZRc029MAde6fvuDzbMNS0k284b0x8OKpGPkcxdBoYgwM2LekNDZRrGOzMhXN33n33Yj7UWhuyeIgDmRfDEDOg4aAtsUDtbRYLCvPWn4wBsFixUq69KRQmj865WTj2Qm4+TeYttYXNBDgRCh2KOaXaO7el0QFpDsYmJ9eksDjkNzyhp3GghSrMVQ/wlY974Hm7Fx/eLwXrHBKseRiN+hWH8VinKi6s+Be/gF/9YlZneXRed/HbX39Mp3ZkQyY9gWBRghqkShA3ACNKC2sKUCOus4UK35AileCShkaOZIEVFmqAKJqP+/Wut18YSsr9lPG46xkR6KvKVbGltCVFYVgJVKlm0BdBYWa/8bGP17HGJJoCE04/3KD7FCullFIYL5zCRupuHKt4JOdS3FhEQ0wli8XG9u7q0Oz8Ke+MMuPu55SNx8FWhjwZMR16wrjTUtTXCGHrYIccR1J4l4FyTMLnlOfcROZB8MoINplXX2JL9RuefP9KLRFS64S2yVjD41pLAhiI8yO++vPsG/8g3R9FWkP0uVnBLdfPbRjMgqxxSEs3xM9z3eqtJF/DYtwwmz4h9AYo4BAvlsIhj7JIcMuHhT7+gQv759zm9CCJceKsHOLO9MZxFbQPZuRxbQntqbyibDY8fPHifQ88MJ/Pvc0a1hIQOFEeLKf8HDfaObaRhKyFEjblGwZwgJlxgFBMu8fK+gn4qGDAGDa58wes7NJq7ilmmeOWJndtYNaUGt9iXJXBZIc2CTYnQW8AazP1UiiLY31faRjHujf80VvOfe7158+tyhBUsLioTPnv7bcxaA5cPLAvfbH9nS8NvRgeVemGgMUM125KiVkQxpDgoSDMl6I1WIJayE+Ln3MxmVkBB0zrabiZZdqWNa/DEP5v2PnTqwc+fGlYFPdJKmQTMRc6mqnTR+yqIoRdnFqCNMP8gQKrBLO7771vNa6KlYkThWSRl9xfNSED7bIfwAficNmce9rxsj28iqGEatXIYWZ4tO9wjtkJnvg87W6VJLFOdNKWltQ8N3AoD6gZdUx6lSY1aUZWeWVlazGN7SVVogKjfMSm/Jue/uDGPO6dSQbxJrWdgNKBdv4AL3sO/8Gf5GBJS3+0F1UarztuQHu3x8E6jiZJ0yAGqtCGBmFYmywHsAAxjA7kUEIsG74eLEivj0IvIVQqJO5+74XJFYxrdEM6pFrujeNKRjdCJo+mYUMkHoSanrRLy9V9939iVgokE4OADKWhF5r3SyoqFN0kIpBbUNCkQW/PqfhPSDERVxazQ8KvR/NHJwxPMnsRZ+G7y/CkSiObfOj5lE+oGEUaHNqyIlseYxutG4DavLtzN3OyOkZq5OB1dTD8wZsufOGt5y/CZlQNCikndAMGDYbze/7UJ/IffhWObcI/Ldzr+BMc30osPJbRMjMrTLy7nV3jhxwNFyXQcFoSciwtf9pnBgsksa8Qzhk4mAyzrdmZj+3tPbws8yLJ45niKYg8qgywo+YAhmBwBDIaTpcZaQobyumHHtq7tF+G0iyouZ6dgw+apAzmYNo8K6LFJKIRYq32mmqXWCBvK6APdalPz1+YwMaLWJ6CQTYJYSOfHch0IhAZ3dD+vmqZdZNY7RANtKEFSeNgO7GmV17yycRB/Nonni6m6uFuwvAADjHyYLZ/gOuv4z/6at58DO4o9ml6egAYBkwOKmUoLO1KZkkAC1+EbA3BCrPwmU4qB3LclAJDLdEykhxLY9hbw2hzO7jgl+45mM+D/z9B0kZ8Usq93jg+reVEJTwsAomxussFOfTg6YdSkNVEa+stownUG0MwU6Wtne9y6s1riiUfrIGmyaqwQrPV0i+e56OGjf6WKctw7PNt8zrDKpLfRZMzxe2u6J8tebF5gkUfmcan9v+HrVj4FzMzHZVqH0wkjYpBXsfy8lPnXrBz4cKBDaQ80BB5FYRx1PZJfvefsefcjOqTNfmn6QmyGBgePOmlnrgGbLAQr9BgQ7FiGoSCOJRwCN09FOtM+0+4QQYNDEMccdtlLZ8V5ezHD2YlE3WdzSM7Hlq1N44rfVVZv5vCyKcKVRhdMru8f3Du3IVSAsswTPQsTtLrwzvIZLLRutGaKmV5smUDU9kom4RLB6vl3oUZHj109L+bshy2CzzfyjpDEXRPcFOPSMBoGWphfZhG32icU7aMiXa9ecRVdQ2vSgTqEhvj6itvPD02jDXyVUTUqjrw773aPvdpqJ+2WePwy7ogwyNKZmFYQSklJc1GiwgMgzFaAyPAQaQ149L8rwIURaoDBlNeZGIZdITGcVbO3rfiqKHk0ttw6SMLjx4xP458jjpQgerurlj9bShnz19c7q3KEOzqFgcS/UKtB6BY03nIaSiTfixJVCiG6TjLuN2mAynk1esIs3L5bAnJ+6dj6CAgbDyH888qHEuwNKpS/a6Q9k7xSGlql3cXyYPlFdeXdOqwdXxrOjgjnfDY/BZVOYxV+8Orbjj/hJ39A8UhMkORTl+yb/yj/LIX6NM+a7SmZyGOza2NM6LQilhYBqpAZjLJ1BQoMZ7QBqAYijhQg60bTargaAVqjYZD2jdxYRcfGpcXq82m7EvK09LRht44rgKUgypYhW0PGJJXBx04d/YcNKoNJJMZTntMW7MBtDDwp2WqG9OWVpQZAz2znPIbmjhhBy4Ws/vurAf7bvZpIf9kB8P8ZXbsSYNVeAUDE468AvNmaj6dTCe/v3ZXTleNtshJGW2f/9aTDCJQMAcquPK6LLcu9v/QDecvOYuBpsWgh/f4dV9u3/BFrE77DLEYSkGZ5cUEhpQqFpYyGdMqlhEVpSalML3CCqyYhSFjdJnSTH0KYbQChu6eGQ9RBl2+WC+cGcvM0KLxIruniv2qcpVgHIf/w0TXV9UvXrgUfPJMJWEzH15zC9oprZk3rLeViIdu60yzOkejmqK1nkKgzHXPXfXCGYKfPtqgHPMT/PA1K85KadaqmKyVmzenppim1PQ0Y/RMr2rWo8yzbUhf03CAys91aQVU0Cu8fPHNZ+cFK+fMeP6AX/Uq+3uvhvyT9eb5pPZV5lU1lK/NsIc0MrAMYymwwThY3l8HWiFSMhsLa8CoYOKjaEcZhG7FSuFQgpm6WuniQ+NgTQ5LAw9pDnvjuOJRDrkQnB9nZiDYYAer1f7eZbOCw1o1Nq1JayLNVDezENrnHkJA0kXHEt1Q2nwG7SedwWz58AP75x4oE3vwUe+VDhre9q7Lf/hvfuwn7z6zs2uju6XQF01w0lQt06qSmc9o9K/gf1ETFTU0cOnCm4gJPYRADhdddSyfvXvu2Tvn94pdWOEVz7F/+DWYNUXgZ+y0hiRchOt9xnKGJWxpePdaIwsOYCwm2W6CdR4twxIiHVKDn34seY4lDVYA6tLpgzCrb+8qrcMheuO48leVapBF78iDoxfbO9jzVUYQN0ON1KU0HRinpUPtypDe5krrUQAT83x9iM2xwqx1oPms7F/iHe+v+rTAo+4ww/0P+jf/3YcfOnPpe3/57nuXdXNeMoCRazEO1lbq8cLOrMbJQ6N1iymxMfFRAJBB4Rzfro0VHN0PtIXVF13/wOkVH3crv/trsbspAZ8xZ++Ykzh5AoY7/NqlVRRMLEBGrqQuWgYMhiE2EXIwDqaBVsghnKKpPLIkQyxPNoPRUGa6eH6stVk+I4FkD8i5N46rACAlvMDpMMos1G4H+0u5WwCiAY4ipQXBv5ZH9qd5eycpaGFTEBPM8gmV+pRGdJoo26m2H2ZD1fJDv7oiaPboTqsxGayqf/PfP/ue95+9+VT9zdOrf/yW+3a2S63IaJl1+0g9SttIfDIhCLPAnDhiWmvyk0iGZcvhhSewygpWx6rC+dKT56/fqd/zNXzi9Ridn2mTTYJ5W207CFjAmU28z6SBFlqRDbRoEIlxGIuxfVDt45g6RbH4tXHutUIUlrldvlDHpWhhvKr0c/z0PD164/jkazHH6IhRU5a0joO9fa6PqDbFAQmwYibRLCx4QzwfwePtLlsCX0ssQS2IJ+lhQwjzmzafErZ2y/vfNj7wUcejmf6nZMT6N/+vD/7Ezzy4e3x5sOI1O4sfeO8n3nzP+ZObZRURmM3G2KPHVY/RKf26tI7PzaRmTSL5xgmLh2YYfgRNIRLuRhWvOPAnz8Yf/tqDVz6dLg32GW4aOUqlPo1Yh0tABekAFovJAA4tTqUx0BWeYIUqpgIOa6wEQ4jiIrRJtPT1QaHN7GCvLg+U4QigwrLQ4D079opHOARwZ5dVAEOgmXDpuFomq1xgKk/Wq2jY/hJh0Flig2nvmkYMYxJGp3Su0GZnFGB8sRZbPF/YmTP4rz86Trkjj8ZI7o6h8P/9Ly/8mx/8xIljl1ejS5qZrUZ+95s/PkoDp4zrZk7lmpw2QsjpcbOddhY0N1VNG0d6ApIOIeKdLIFk4wg/wE0YX3nDZdcV83pivNWnhM/W7IPxmcKjNGhqnj3wFEIrDGRtQO4pZd2DfCBL7MKhhQkqOmzgctTBnsRMv3LPlJUOjl75CAcBbW4ozpGK3mGswriqITyRZZKZaGKJDMcJGQ0sPAgdRPLCMuyRhvQ251oHZ2YsGSM4GQkWetUwjG97I0/fM5L0R+EFVCtKwY/+l8vf+89PHz9x4HKaCK3qeM3G8EsfPf8Td5w+cWyodJpaUkH+V4rfOSWABCs/A0I8ibNpLhyXJsjCDTAo/RqhlBISJJbV771w5cQApB6lQAWTK09K19ZePrmVpNTNMqE6kFGW0gjDxplNJ9sANWwwm5UYUmxIn3Q5lweVkTSFNGemugPYVQBvAOD2ljY3OdaIYkIlKuTVgxhGlPWbpnnsWV5jLQbc8HtryGcqZhtHrInOwy48hxLDIUaICysXZuPHPrx8y08Zmbnmn8IaK4aCN71z71u/++xsYznMZi0GMsTyvrlY/NN3f+JhrBaDudgiZPmIgT6PsOn51bLk12cAHda9ZdSV6FTeqzKQFoJQePqiVhWf8bjD6U+coIyat3TbO02hTIkFRAOw1rBIJgWYWhQ7S7jJs+TKYyl+w/SfAFPK3ETsX16tLyrC7znPsjeOz9R8CuDkNdzY5ooYpRGobcJOqSPaaBFpSliLVtJ6AVTMF2inf7TPtKCVxmKSRpXKV2T0DpPRIXdUZ50d/NyPLD9xN8qAT2HvGEcMBe/+0PhN37G3txpnG4N7y5Qz0lTpxzZnv366/sjtZ3Y2h3Epr/KWMZaMxtxbMsBKk0V5axdqa5oibzK0+orc2rRjjHxEjBToZ/exHKe37mf6hUCYrIBmSkf4UPEwpbElc3FoUKBbhRjSjIlDnmOVFDKupbFDXGqsCe3T3QODwbi8rPAtUfMp7iK3q6aO7aDMgh2KSGMaE/kLfUa+9NO1Vkk/b9lF0yvPGq0LjSOG9bGWjKPk4dtmSkMBQZUYXcMGPn7X8vv/0egV+pRoFoSxYhj0vtv1l/7O/r2nLy42Rh9BmNwa1zmPy8cWww++++yD+8uFsfohC58W8Nro523HO+TEE+yPlkc23V3Stnv6EimWrYKMy4p6pez0RGQ4oJlosBG6RJve7cDEyAg9Wxj2DBGGABRZOsBBBTBYARmyemgwDiWRlMippa2Wk59CMwE7ogywI9g4rr8W2zsYXWL0jiB0mHFSOafUK2/9CQJOtHKEbXnLHWhRqZlCNgGljRgZkEc8uNgkHQYWODjf9f/2ev3n/93Do+OT6R3xJh2Kfu0D/ppv27/zvgvbmysfK6HmeGhGmNlg5vBjc37ggYMf+9DD27NSR4SBolrCSjPrIQGvqJ6LufsE7zF6YdjDyyVZNh+PVcBUpRGZI7IasX9wJfQMIOK/AYOnS31gT0ChDfFTTStjTUJ7aySWDOmDJcdcoKyAM6a8LRhleW0pHELsJA0ax/BWi9EuIfZ+Vbk6VpVT12Axq6Pk1Oga3Z2wUnKXzdtkBJabTeIUKEKKTUXpsmnN08GSKBouF2yvwjDHi+BDJRCi8BhEzMeqjmFz+cP/anzz693s9984wqrTDK99o3/NN188febSzvY4rpJHznWVlOxJ1cetQf/hvfc/tL+cmSn+ijWUa7F9CB5BSg5AoksAm5OovNl5CY0z6oZgKgQNpJJOVCegA9d+xWd8V0kvocShSKiYUwwT8/hpDwytPUqzAsxwvJDVsl1tASMH46whowMwZ5xX0umnMOwIUWhGBZLWhHZheetdHXtVNI6dTdx8nSrKIUcfoMyYfrXr8JTmR2GZDdDyE6EAL+J6Yin0ivND/sIWzxz+vORh3oNAWUuwJ8oMmNV/+Z1688+lVDTfmb/rlhHc0It7/p3/0v/6d44He/uz4aCOspyIEvULE6L0FqGPqtulfuD03i/cefbYpo112lOa53tY83hbYTLLHi1YiW29oTw0K2CsJ2xPVEjVIzuPMC6vpLfIkBQvEhwUeyqtRUPEzzDxKWHimDYeeqCh0UdgQLF2f03WecjkwvUDM4sW44kmi5PvawdHr6LDym2P52qkRBmdqKTKwMw6yDYhMylpyWp31pSGtge50vzNXOai0zxMAlNBbhEQF6l/SqfCGFvhpFhQWAsw14Hqv/ie+hP/AZBKAX+n9iGtW4YZ3vZB/8bv9n/2Hy4Nw8VZ8Tq2sMXMLBSbdFeZvpiq4MLZj3zk3GV3c9QKlyk4SYKLHtGYFR4fybxMuMur3CPXPoMg4ZHPZu4tJlZpYaClc5yG8s/8e4VTWGwBB0cxFcjgpYUkGGs2i9hTpBkRn1/MYg0ZGNJ7hu1gsVh/2EhfSl9SusW/0tocO4z1IT+iVI7h6DUOEp/1jLISFow9Hg5oPjTleAm5+NqMWs2Kp+Hx06TbYlRbmOKEd+Rrc631SAsGQMlQp4OlyW7HUcPcD7T8N/909va3l698jT/v+VZKDhS//VWgicQ++oB+4Cfx2tfr3NmL154cD5Z1sh9unn+ZCtNAmjADEEWH7c75aw/svefB5QuPL87VcUaYRMlBZu5bC4AJ+lazeG57+iR1iZEr8pngAT0SbYhy7Y2wK4CzMPWuSJwJfk2ukmk3JCr4foKY9DfGnhFPkBy7CHkYzrZJ0yOyborHIMKNVoIVeGqj4vcKDQOO6Mxx5DxGCABPvZXHj2l/j0M8VQDOh0htl61DDdKNIt53RpNlmAikgD8wefgERoB03WPLhDQ2QVM6gvnkx2dwS70LhOVKVmy+Vd/+a3jPu/nyz8VLP0/Pfg6vv+G/W9DzZfbQOXz4Lrz1A/jhn/X77qs7Gwc7m1ouYeGy5WiKkYByRaajMsxUR4iBQiysnN1f/dxd51/y/OtQgywOOQmXOyVYWAx63Jrd4/qauxkS7HNrBxgF4BhcUjNhhMPIqim07DM6oE9OQ4LSkcjjhl7bBubpsBLbWOqTCJT8aHo4W+vBaHYDce8Ow6OKtROxw0iVYpPrV+QWGyX1xnGV9A0BN57Cs5/CX3mnz7fgI2CwrblmA80mIyybfHisGfNOGfWJf0z6+3WQXz5qpt9LQf6yxhQM10lTu9o0kXWoSQXZfLNWldf9/PiGX7bbnozrb6mPv43X34CtHY6VZy746bO66358/GF+9G6cu7Cam5/YWa2WGkePXYJrKX8T7oeyho68MCcAE0L5nYI33X/2rF9XrLickEXrCdlN9Yysc9SW4mYEKqdkKwCyiGZyIp0+WGNdswabGGd2hTw5gBSYRJufzNfTtygMlpj5VAjKLVryWqYHuwfY3QybWthug6PbQZsKNJyUR1hNXmMJkKGx7I3jKsBHq2Njjs99Id70dqYkQW6bC83nGNs7IdQlTUKvlsdhaPmOkDTFt8WlTsHyYnskeTLD4nFMT1VmPq6EeEeFESE8o9biyVW3dynTb34Mt99l9g5Vo2ZYuR84KjGO7qVubujYBlajr1Zx5dXh8GhHuOy0vzcFn1glJMkICIJvz+1j5/Y/cP7yC09uX9jnkF1DkCxjl1Ixn27tpKrDWiK1ixbUr+YVFmiI5eZmRWLBZuHuxpWCcZBmYqG7cnagtdhcTpei3NOaG5OngT1dMtJJoEhVcdCN7y/TxcSw3uAcYoGJKslrQQvl1KeeNtwbx6NZz3+6rjmpgyXMSAcXM2xt4PyBDITTJ5dvS2JwaWHLObCGngWHjAVbmvL6sZoWT82FNOmlzklwz0NtSYIh8kcMcoCYbXAwFwFTJYppw+SmOpOAccQorw2bZGRMRdQUWRQcizgRUc5GWIn4KYtnICqHMlw40NsfuPjZ1+9qr1YXPaBdyqIfKN8vLkEl/nQOCzq5ZGD1yma1qIl6X6nIOpKwOcfsCnk5RURCyGtaHHDuGkj4wpJFj/W8aGZJgkuYCq3rpxWBHQ7MZFomSFQJwmD1vHdLJXuSlKSOflW58v9KhIRnPYnPeIpdPpAVCdCMtj03KS3OzXKXjR95aa5f7SiriGKyYJ1HgiRZzNlgc1KW2Uf5P2PiNbX/mWGUQQHS5H4R/5N0YFm1HLl0G2XudJnI6jZWW43wCCVwydcExMRlPBmiRkK5w5fpVoyCRpWMY+JimL/jE8u96i5Up6fIzSK/SpFi5Ukrr3GvFb2mi4B7fE5cY+Msm6aMctSYSq5ZYONRDL78vXUOg0pmbDWGDZrDADAIRlFhKQqKA9ykaJaxChoUkAUzsDoMzVHog4fPoAakWt8ANmvSIMcR3tbJI8kdPYITR2wr2xt48bP49g+UeMY7DLsLs0bWaCnuLdwdUCNx5E7b3EXVrjFYu4tOmWSa4khy8rXMOVojhCV4YaKFLl1oLWZyTY6LZ4VMo9PV/F88aViTVWiz1eGUgITMKggCxhTrSNAhIyO0UpsD7zq3/MS5cZulehVQYB5DdHBIGcKV7JBtJCLgJZ7LniS58FTM84qJTlSoerlpG0Np8def4ZeA2GjmDrXLT+4OyfhLn8mIyVGS+CwvUvGwACVvhLq0ZwVQpmNbzKZ5sEEQwQIO9ZAgS58xC8U+cfz+egeAL36FtjaRs+jovrWhoVgeVFq6Rp5LJhvimDJK7ClJRm82PQ1kb1luOYwQa0pYiKOSieiha4iEozbWJtOCbMxu90n2sb77t+jWOHxk90oN2nRYjKmhHXgOdTvSWJqlqgmam5/dX9358P7gWFXkxiRUmcDqqoGgeM433mRwEYIXw5K7quQOD3Fc+PAJqIIT127jinm8pkIAU6Z0Wm9YUXt2RK5SEL0gRk6CrKT5aDB+bDAW2mRKWjIXMuSzYV/MARbeggNU6O08H8crdgLY1bWtQHjKTXzhs3RpH6UYHVrMtD0PX7eWm2qCQYVmeVidXMwlm/w1mi2WLDYONnZYJsy6xcsl12EPiqKlz14NHD6hOfNoGWHSx4Qpq0KJEi+3hoA2PlFjFKkpp4K3kYZdDirSl/KvYxTNYUlSN1OZUQeretfFfbrVqiq6szaOWXBDq0ueVHSv7jFtO0ZH5HjH0uVuXuGxKyVpgbY10zWLK2RPQTtqqLnsCIJlpxB9EtpboczVvGVpseOEEl8oSodRgzVZfdLA4h8yRNaCaRaWxdGUPQ3W5NKRDGQ6suBoFWYDvuZL7C3vhiIbqZS6u8nz+8QQA2kMGnlaiNyivNeDZKjG08ncjGuDh8BKDyeqpE8YwPA11To/reU9GWQl1oIEPvILKplca7L3IYE7GILblujcsgV92rEs0P64q1DRAJv58jpRGlK95+KyioB5GAG6ClWRhyYjPV75jIOQRqUOIxOUIQcpD6DYg+FB4+h43PW4fn5FnFRyp0hTtzyfxHpFz1wL08TX4ORYFG6RMSRC7cfIPL8Q5bCVYvxEGp0syDQVUkH1GjYnbN879VXlqoNIX/pMvPQF2F+hFFGqxzYqi9dmIVssJwOWxjjM0XLiUk5GxB4rULh4EGhJbVNCSWjtW4pAgCi5K9f4IFzJxTzcEXwdwojcFzLXIPD+ScCuIAo0K7zMVyIVrmbZ5tgCo7m2/gOggTi7rKM3KbzLHaNjHGNIahyRZsChSNyVUpKvRsP3dEHXmO8egbhu4Ob8imA7pcCMOSNgirsQgsdnmCTOChDchLR8y++grcOCvanyhdKcq9fCfDW/UgRcakHBV8qUGjx2BEeOIztxkBgrthb4wy/E298Dl0vUzrxubtjFpc0pKm8p8VQGp/dvcjesdRJOyJpFZHPji8mNiHGkBTnFezkGE6NqmoOhQhQ8by7TWz66RMC3CWsgyEfhixwYpcI3O97ehFfP+To+mnAlJaiivbBZCBfdCDdoMLs0+goKi2MorkFxaqUAEz1OiM1hgJKLZnTK4FU0yQCvBjlK6IjFnR3dOk/o8Ap5uhIo6UavDNGNFGhbt9JmzwSDCTSm8U5ue0pNU/MUm8wVIr2NpKMASV4XoQHxkkpWT4lpUkcSHT2yEweQWcd/5BV6/A04WBWTrJhObdPMzBp31JpOlIonFBiGGvEDj0e+M47762h6NR8gNG1CWAcJFkNDhDPExOGUxNp2Bg+DC28KCkWPkDxWYklyF+BT6po8eow3OgIjGFZJLJtYIwyVlqGEsD8CUo1WYA5zsVaOnhinR1RhnGDFhmXAXdWbTCv+n7cZJxAkp1e6AFmdV9y2uwalrwSEo51OPK6qlnBWNMv2TUl/sLTtiXd4aRlsFuY9Dd420CJ0VmawgSiwwWyyMiY4ABbEQdBCrKKe5HZVDh0uHNvma77cVk4rLFA5uWGbQwjsm3exhWApDowNHm2u5kkONDYcsJ3lGG+iydorm0D2i5S8u6QQg8QG4Al/tJieTD7KHQfZOuKR6BnynGoYKdflxpRW+wNOS4paiHaSnjLsJY4rmBUOVaru7nCpgi6ruSwxFbC5GFFtEHIPiC95qq7mAOR0B0fDE7Z5zQxXEs0pVWwGMM8oINfnlUzmC1F0+lWHXZgFGSZT4ABrXsdpKSnLFQYcLDJZ0tN4YAbB6VCMXcul6Y3jausdgIQvfple9CzsLTmjbHPgNRuogXqaRE+WD4IhJMuFOOWmIJtRINslf00CkQJLC6DiMNcrGKKelIdoEJBUGc95Vw4djzCag5BeXGrZozEOBcYRVKuUqmjtI5KPWCtpCKC4Elnae1tBGWgbpXjF6BhrivoD/69CrXQxA3fzLovq8sp2Ko5pKHlUmU3rtlwt8VnHSF5JxwNOoXWMk7ExEnZyo2ztI1TzGW7RkhyRYbFQ/NqSgSzB7+KAdZJbpigwomQ55OiBYMFYnM+O5tRx1BtHDB2b+Po/ya1jBiOL6nVbWpScXEMlm7mAlt0kfurWpAlJMw3OeC4gYXuLjLQ356HnjEHFFNzB1EeleNsJudwZU0ZDMiDR0waDCi+M2EomtDJOKZEg7yhSyWtrPNjMkuuFRk3Jk0qLMUMxbM+HChtho7M6xypJVaweqbF5S64Ke+dYYdSYpsxQyDz9UA4caP643fLkbTThxhWyqoS9KMybz3B8l8K5a7JhAYslr6eEai0vZsgfvayknoVmVjKnPhNkg4NuhIkzloFlKCUiQxupL/1c+sRxlSIdEl/1An3py7C/QqHXrWE8tsEa+wAdkS2a4sg4v3q6CabOOhJWgsWJFp+amcywNOXIqSWeay1bkck+FulkriKZD5R4RxqO15S1qpFSXZCc8qSFry252qIUp6G4AOTZdfILDXI9h4AIjUZeM58p/wio3lpGDQ6XanVvToLheRe7UTJIXDUmqVhqQqOzZHnuSTs2wxWUxfSI2wrb44C5j1JmiWybUlZsIiJjx9SEs+lvX5r2IHLbMoFJFrbGlsKDQlhBCXJHTmXEZLLWz7FXaQUo8PVfoSfcxGVlIcbrN+sQL4FAzIK+Ex61BSStrGX1GRbJJnyY5uDIfArqsTlDzqCJyo6W3xI8K8md9HgaBSrZVK+pYHdBNRNH5fRDz/j4qofs9tMHL/V0bJlkLZQ+zrQg29F5znLtfFarx0pSCXdUJQ2sipUcBXer8ZvLagOAPTINRQlpSDrQXYtbjuMFu1fmz7xxRpkhl0M6psT5OtSAMTLIGvXL6AmgghN935R5K/kFkxgW8AcsZhCxiDOPV42gmkpcNBJJbxxX41/S4I5bbuBf/kp6jBM7s3pqix6wYYyt9IDL4vbmmjwEc4Q1uK2z3jI/IP4J6XgjWcIWpBsmFMOTGJEJaS4mRyLznwMHddBVIXd4lQg5D3cMz7HGspPlSdWaf1mI7XJVYfjdibTwL95dDNct5ssxUE+6W5VVVxVq/DkdLnP3tBR0IfyJw3wjP4fuAeJgKIv6vC3evNEMPK6othEOBtm7YwxjQRMVJLfPMkc89CfRK6hCTxOmmDtg65A3xexGykwAitFMVmAFFhbWa9N8ShlT3RvHVdw7qvPLX8k/9UfswgrzQbxxUxszhqVkJDiaBaClfF2IaO/cJqVV/m+FklWUIk0SVEurDXsLIG4eKVmTGl8j0AML23BPl+DQf/haTBluGkEIkyMxErXg+fT3b6q8MPJpcSmh0jSDgeYw0anrtxfHZ7ODUYDFuUZSlWqVC6MUCQl16n15yFkDwg7WzEmAROwWe/mxK1L+SdokR8zTSZpCltTIplszgxUW0gE582GRp6kESpq7U2ZuiUOqpq2Qkb0SI0xBkz2BcV7jkb3IPlYaB9L0D9/0J/jy59rBUsOO+Y0LBWKm8M8PrWkb9+MjebhA8/jKENVQQCgdKQWjt47jQNhrhRysQQSJPsa7O04UoVJpnI7Gl1DzG2/pR5b3gUywTi5CO2/kPp66rQgA4JCJyzSowNzxpJ3NgWXlcUNp8hOHuweV1nNn0SS1qA5vaotcWIS4+tQ98CXHy62LgIyvuM7RrJqaV2CcTqZArnC8b8EryewAQn7SdHGyjKFpx5cUuYhSY45m1mxRKuszfWfy8YHgY28cV/uFRcLJXfzPf1bXXWvLpcoNMz8+ZxXjDtFCzZvOA6kB5ZrbARymiiURPAnpIEKHMln3pI4+BfFNb5qHS58OFN5+hRo4G2p6byQOaaKlN2nsFJKamVFxhm0v+GQkRQKRoIXxtp3Ng9Edqu2gk+cbt9GhtFyPucgioilmrYyoC9iwojrrPnZvu2b++Se4tt288jCOWNtaaF8qdmIeC9jKGMKduMenPMBa67XJxktohI5oJWyc/4jbWRNpLFmkObYkoRR9VTkKQ0d1POtJ/LY/R1tAJt0yr7OUnwhEsRSSp+RkElcyOZ2hgbF8+4WvV9WUQIKGv0lBvlyfVxS3YXeAHvwOOSP12SX32vijQUGlYl/xxicJlyomumd5+YXRA4kbggmbiQ6ZTzYDx+q37GxeW+b7q0RdkxsKVFoMFFV0YfTU8yeRNEJwhZqMsiIUr1hwwz5vZ7huDr8yX0EKaCcZ9RRb6HTMcSxtxLBmUG8JZ5X4gTe1T1tAmOf5IIAdEqo0NipD0mKNjR5WjmHE6L1xHIEqBnd84Yvx117NpXPYLrh1UUObkOgYJ6lrjhFgxZSiIqdFOACMqTShZPDIjmXTpq/1bxHzzBxhIwJJKa93h4cNUPrxJLARm4ilQ0C2hiBsWfMsLEwzMlPwlVia9RhdRZjRCkqBPefYMbhWXmviGmiaekUuSg0xm7N6UkgDjnVkdqTLXFChHQx42sbw2dvQlfgwVdspK5TeboVKt8g8skbaTtBJYcrg2EYwz5trHGILE8liO6LbtAGlj2Am1BrLEPmzqZ9tx3xZJ4AdpZ3lNV+M//GP8dKIcu0M184pa/Gy+cbEOiql5XGkClXtKtqwdSbOJtGnQ0m4h3lTsR4aStorfH1Vadr6poqS1vtM4Kjx1eMu28LmKCNUwnSjwXMDORgLzIgCroQn7Gw/fmdrb3RB7jFE+ChWZyZGxwYf0EZTw7haRn0TysIoRzm+sfunri8b5cokNsW7eWE1rQVsAjsm91gAiuBYBP2LEx+MOWiEi2yDjoJ/aza5HCu3kqasNUMpMLJMsjop1NLzYbbp9ei9iYbHbOOQ+Ff/BC4v9UM/jZ3HLXwFu7CSBWwJwmThtCCAnoq32PTXislgekmQyYC1kU8Ts4Eup+dtrqFn8MlXLoxfJHi0IHkMFrnfhPx14gSo0UfiwOPNp6Y9BZvIG2YsEsAF9fzrjrtU3QdGK4qLQQ1efInfWgAt46Ey5cnoXiZ7RbJCW2Vz909dO3vy4kpdUnJMPD7HbCgybwaBOSKomU/H9JFZfYRMHk5wJe1MksavRD1gCi/GCU9iOpLSWmMyA0qK3OL14tLOYCdCVH20eGCPxYkDzX5nVvAtX4VXfwkuOXXLfNywZgJsMWNOmRoNEJu0J0i+YUY9MkJNqgS1M0RsMQ079DytTAYbU66zopFEq5m+Ptd0ZU7vB+RO3VapBF1D4ZvCTiMLOAAz2qrWZ1yze83G/PKqVja2aPM/HtsBxR2ejsSYDigKQWx4kDmdwmXOX7Kz9aod6Ep/4ZyYYWOOyJXyZOtNnmChW5ko8pkXnlAFEgpJ6X3BFM6GNmVgrXljmhMTloti4/QyD9gnxOvzZ9VXlaPSO1yYgd/2VfxzX47lnPa4DSwCN9f0gghokgzjjEwv8QZ/epOlqs2mLqaATe3wSmfbWFJrDTbSRNC6g06enA73jHFE26xTNodctyNAzsQwEI7rbDnkaU5gZsOq+s3bm085fuzyQRVRhZU0Omv1xvuiu2pkzq8B0bRBr5WSKsyrqXC86LMnbR776hMJFl+xP1YAwHVzO1Y4hh2jNZ17CT5wldFMQnjLprOxkjzaHNhImmwttIdZ2giCzgIryQqjsVj6QhdrVkqgmZbAtcA16n4cR+7IAmJW8Lf+FL/uj3Nvo9SbFpwr4+zZmABsV/npuJFuo5nqtn53N7NxZwQbmMdykjMB3G161zU3wLaurF/6LTI+uRxiyE48PYwD5ltbJMeSonhYooAz2OjaXcyfc/0pr6qT+6BYgVF0saayPnmrYyIqcrDmaCR3ugvGuo/jt1x76uuuH44XrG3SrtDnAYBbtvH4TawIltw81n9m8rAgEVOeQYsKbhywZmLevNzaitj802NmCdG9yUpcvNZqBAizWbmV3OYRFKw8phvH4QnyG/8k/vb/CF077F+/4MIypyQunGH2QqugExO7NL0CmcnGma0a+KbnzOre3qWhB4n3ZA081JJX2JYYCvR0FlS7D8AjnQUQUWmyfHl7W96bfUQxmDSADi1ozzt17UJcSithdFSHO71KrjFsiV3uXEljqOlBd4xVVWHpTneK8ANtbe9c8xev2XzihuqV/g4gUIWNYs85wX1hGIiiYPnD5KGCTo18+rRPzvFh4SSLaSIvW0kaN2WOgmkdnBGT6QAWWjFLsy9Ze5FsGD4r2lIHR48wVvo1X4jH34Tv+Dfz+5b1+IWlRgXqSMATU5iil5nGGGuMMxPNK9JkOOlTuWOnKV8koaeere3Dyu4t98xwzQtLDCXuaEq6mK/VBLkGC51biSOjrFBj9YXZs09ds1VmB7UWZJhldKcBcmpIshcKMQSN1VBdggYSUM38amrEfGvz1Ndfs/FZM/nVobuIzvbCXc43yugjGXtHWjCDkZsdMX3xnYk1T5P9NJrOLYIUmCx1JOppLYC6xUCWUDIVljabGMViO7RnyMOntq8qR7N3mKE6Xvkc/Ku/pZd/kV08MUdJ/1qEqTmb1jG8QlMvySkFKQw/WzocEEEKEWUA88kCMK09sAY+p/8Z5NF4mSm3CCarC7kauehEuIaEi6YZDWAppLs2h9mzTp3astneWKswCpVrOnmFPLjkLlf8ReLwkEOPJxsNbqwjNrd3b/5r1x176QYqrhaZZ/zIXnHCnnrC9oVSLOSwkV036VBKSEtazMrkKtu8u5KzFxEWa21c3mibm1JcVZjwBszS1pFcOp4h3MIjmQDZG8ehCm7Y0x7Hf/bX+Zf+Euvj5gezUiLjL2VO8V/WUplS7dVOsJmeElNIhiaFYXBK29KbD2iKtHzzJiaa4pPmBSoPh76QSrTZOYjRKaoLGZvCnqZWP7nYfMapU5s223evwEoKyHP0OKnkH6ACTSZvlWk1GvS20VGdGjju2cbW1i1/9cSxFy/gVxNxOpxiTw16xSa5NXMKBd74oGJakLoikDzN29OVkfKJbxqu8pNHKd0sNEn5QbPwqU6HSU4e1CTAFfQi14ZFGnlvHEcbLjW4sDXHN/1Jfu+3lye9YnFhmMtRCqyEPDLHVE5jQXKOkqPhGbkRljqtYRgzSWBy+ZnIX9NtNv13Go0iTc+dGeHSnppcOyaHjwRhtQIVN+3sPP74CYoHclhwGOhxhXWNiDtO7ttpZQgwWkbosUS5rODg7Lh9w+YT/9bJYy9eqF59L5OQDv2Ja217xjopZXmY15kiIzS6n0FTCl6GqYRpZB5u269tJi25lGS0U46l8aIo4J70lNnslbOiI/oe6xjHb3NqiZngDz4fz3yCfuj15f/6Pxd794xbM6dxFCw9e9sjBjlAeCAgSA/+9A21OKqKNvEzwj2L7gGapEMwDiUxBXvIAEt+qJnSdcykFoctc1B0YWc2v3lnZ3c2W1Z3w8xUXWZxAqZHLLtgRpcTqhCkkkfezMSs1YdZEbA8hxPP2nra3zq+/fj51YJr/PfDI+DCszf4+Zt87dKORzJvy8+abiKKNK4W1a3M70sBAC1zdFNir+kikx8IOMuseQ9mazKTOJQvIq8z+hFtHNSRNXD/pJ9anpaeb/8N/Isf1FvfOM5XdXMmF0eEVKxZ+TTRq0eEU5BE0nKUYnrwZSpHAqUV6aSRTLB4+peWXki6pZhTJVgI7ggrGWOJplU1kCc3t67f2RhAVA1UgRdyEAoxpODbC1XkAzFABbVFnVYjivkQse0z1YPVDrZu/aLN2/7CYr5dcDW/6l0w4u3n61d9XHXvoBSC3hLumNR9ePaI9CnIKZwkzFtscDp0hKbWot1EAmRKYVgKCRTjYCiiG54xzP4BeMwmyVNvHI+p3hGulIa9Ef/5v+E//bjf/o66OdYyhGFnE6oAYdYZhxJvSQmeiY15MCGRQQhtL/GcT+Quwmnhh1ljaSmh1xWG5tMTgtfghMwKdxYbJzY3tspgEuUDYa4ihVfmDCqmIhXUwTADBrlBBT5QhSiqRhVgZpqZaznsnLRnfu3WrV+yiYh7vMqflVUoxPec8X/ywOrYwYgSJzJkS85jVQZn0pTjpqWDPKJ5W8RQpDCZcc2ik2bMFPNiKIZCzoyUD8P82618DuA8slhAbxy/22cXgDOX8e9/Wj/x4zp9dy0rnxtXTarm9DjZTu6c6cdjzZgrukYsQnmrVUSHxf8wGugpegOpGgfD4j7ALCwxhALOh2Fnc2N3Y7FRZgbZ6ANtgIdJTaGbMEADafAinwPFNANmlMGHyMkWimqhismWWmjjhs+eP/cvbuw+0TLI8ep/UMYr+/yoP3N/fddD44niIxVLYJL1W4pEvhnCsKkwCXZBxW1XWyaDA2vTQKrQSqFJxWjF5sIl41fN5n8Z0JFGEHvj+N2+BN0zGu6jp/GDP4OffYPOfNw3x1rGDBnwZG14s+3xKecxukaLfXPl8SV45gnIWyjikCglXAXBJGNxGFGEjdmwtbGxvdhYDAbBXAWYEQNgQHEZNEikijQDDT7AZ0AhZtTMVMLOij5AVsQDt/1y3eO3nvHq4QlfYmUw1SNlkhlDx7sv1D9/Hx8+2N8YollbsvotkIl0p2cTyzfwGWGvBihtA63hpMaBoHHWVptCLohL5EuH4e9b2X6EwKg3jsd4+1ADLoEP3osf/AX83C/r0oM+26+z6nUlr/Ax40LjqsKUq6TKLRWz7YHXDNjVqAOckiDpMmIgByuL2bCYz+az2ZxlBk4pQtEvZuAMMHKQF6XkoogzuBEzaIAXaoAGwwxeCop5cdSVbW7gs/7I/Jl/fHPj+tYgj9yLPYCa113GN96/LPvLYWC7N8VBrOXVJwO4Rb1ac4ArKb4PLg3jkkUWC//ANExfAJfNbpvNvpe8lUcWE+2N45NqH1Lipu//OP7jG/HW9+pjd3ldalOVo9d9YpRW4dDpHtmJ4Vkcj6y49jUBP/Kg0sQQBIuVUjbmw3wo82EYQrHtYJW5IjAsQ1GFgZoRA6wgEA0ZNGvxYzOowAs0QDPz+QBfauFl9+TslpfgeV+5OHEbAB6xQeO/qxEYhP+0j+94cIm9VSkYcwNJ96TMA0U6m0vJCnOIYV9uaVGfRvdQMZohVHJz4NJgTxjm30U+7THQNXrj+CRmYIc1Xundp/GGd+G1/7V+8E7s7dvmzOcURmkFH+UrxyqU6i6ZBT9TkQCX3CEroBUW42A0G8wKMRPNUVymTPMwsQDmKh5+XzCqCAVxJWEB5ox9hAU+o+aQ0Wdwk3RALHHylD37VRvP+BKcekYEnE0upkcaqAJM+s97+PZPrB5ejrumSjgC4wAMlIkuJkFccUAxGdii8RBBbQiOuUUgpA3UhcGeW4Z/YOXxhD82yFG9cXxy2JvgSuzj4mW976N87S/72z6Mex/i5Us+m3FGzOegUD35YUHdYBuhJ6FmOoU5AJj74BzaS7o4ikBpiMYBRbwhpSIMpAnF4xbLgZgRhZib5qYi5ygtuTnMjl1fn/ZyveQrFru3KjMcefRbxvTDqsJAvHnfv+W0/ybq7rLOzCspwiZjNTS/4ukHE6zQhnEovNfIYpiT+6icL75smP0N13GjP2Yolb1xfCqeZoJa+wB05jx+5b349Y/hV96Hj97rFy5Do28uMBtQWDxDD8LkR5yCg2pESqZSfuYsUED4dJ+LcAU7owAFZu6sMnAQBqLIQ8Y5M18YB8GrbOSxTRw7qae8cP6E5+G2l/j2iTZlCHzs0YYrUIB7V/qnK/3IuXFVx+0qs7hIpfqdzcEYgBlVEEy8BFOhAs6ISixnw62D/TkOrybB/OLojaPX7xn7SBfb/MiZC7jrQbz5vfrVX8cdd+uhi1it6CufzzEbUAQiaKAAqBEe9nQ17aZY8/4aE4dRQ+CgwgAUg7lM4OiDSMdAoqruYaPY7iZO3YQnfZZe+Lnl1BP9xI2WdOjGZ33sdnnAAI36FeJ/e3j59qU5febjHJkIm+o1a/lXlriGpe80x8J94w3FvmKY/Rnw1szze2zJN3rjeFQ6SDDHyqEH0D2n8et36AMf1Z33210P6oGH9PCZDI/2SncNRQYMhIXa3QyjF2WcWAEGYQCLIMlEVPlKpXIAUDEjju/iphvs2hv0+KfiOS+wm5+Gze32R/IcMR4ji8nvvGMCBEbh5/f9tSPf6v6JcUWpLFcLYjAbLDj7GeY0Ej6YmZnxafP5y6QvA59TDFIly2Pve9gbx6PeQVpq9boeOKOHzuL+h/ngGdz9AG6/y/cu48w5nb/I5QHGJZZL+AHgTphVDcrxeGHcnHF7E1tzLAZsb2lnB7c+jjdcz5tvwTXX6+Q1OHXjI36zsN5hFzP+lt6xVvy63j/yXUW/NvpHx/qwuCL2q/ZrlWFrMWwYjkE3ki8chucCzwRuapFYeqzqRHvj+LQuMnF+tUe+1qrLxfMXcfEyDvZxYQ+nH/az53h5r9YRCPYXsTXnsU0e27VrT2FrQ4sFt3cw30AZHsG9CISVhiMrk/hUby6pmHWBuEQ+JFwEHnQ/u6rFeGo+nAKOA9cAg5LlMUYK7WP4+9Ybx2fixSrgkA729+4P9QieVpiGonEf+zLy+/huTgMIf6cuo4zafKx/l3vjuDJWbj1iZMA0LDzyh5Nq/UfSLnqn+NRiH7/lu75uEv073RtHr169fv/VQbNevXr1xtGrV6/eOHr16tUbR69evXrj6NWrV28cvXr16tUbR69evXrj6NWrV28cvXr16o2jV69evXH06tWrV28cvXr16o2jV69evXH06tWrN45evXr1xtGrV69evXH06tWrN45evXr1xtGrV6/eOHr16tUbR69evXrj6NWrV6/eOHr16tUbR69evXrj6NWrV28cvXr16o2jV69evXrj6NWrV28cvXr16o2jV69evXH06tWrN45evXr16o2jV69evXH06tWrN45evXr1xtGrV6/eOHr16tWrN45evXr1xtGrV6/eOHr16tUbR69evXrj6NWrV28cvXr16tUbR69evXrj6NWrV28cvXr16o2jV69evXH06tWrV28cvXr16o2jV69evXH06tWrN45evXr1xtGrV69evXH06tWrN45evXr1xtGrV6/eOHr16tUbR69evXr1xtGrV6/eOHr16tUbR69evXrj6NWrV28cvXr16o2jV69evXrj6NWrV28cvXr16o2jV69evXH06tWrN45evXr16o2jV69evXH06tWrN45evXr1xtGrV6/eOHr16tWrN45evXr1xtGrV6/eOHr16tUbR69evXrj6NWrV6/eOHr16tUbR69evXrj6NWrV28cvXr16o2jV69ej836vwHadYXzPOgOmQAAAABJRU5ErkJggg==';
|
|
22
|
+
function cachePath(appId) {
|
|
23
|
+
return join(config.session.dataDir, `session-avatar-cache-${appId}.json`);
|
|
24
|
+
}
|
|
25
|
+
function loadCache(appId) {
|
|
26
|
+
try {
|
|
27
|
+
const fp = cachePath(appId);
|
|
28
|
+
if (existsSync(fp))
|
|
29
|
+
return JSON.parse(readFileSync(fp, 'utf-8'));
|
|
30
|
+
}
|
|
31
|
+
catch { /* corrupted cache → start fresh */ }
|
|
32
|
+
return {};
|
|
33
|
+
}
|
|
34
|
+
function saveCache(appId, cache) {
|
|
35
|
+
try {
|
|
36
|
+
const fp = cachePath(appId);
|
|
37
|
+
mkdirSync(dirname(fp), { recursive: true });
|
|
38
|
+
writeFileSync(fp, JSON.stringify(cache, null, 2), 'utf-8');
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
logger.warn(`[session-avatar] cache persist failed: ${err}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/** Upload the built-in avatar once per bot; cached image_key thereafter. */
|
|
45
|
+
async function ensureAvatarImageKey(larkAppId) {
|
|
46
|
+
const cache = loadCache(larkAppId);
|
|
47
|
+
if (cache.imageKey)
|
|
48
|
+
return cache.imageKey;
|
|
49
|
+
try {
|
|
50
|
+
const client = getBotClient(larkAppId);
|
|
51
|
+
// SDK returns { image_key } directly (not wrapped in { code, data }) —
|
|
52
|
+
// same contract as client.ts uploadImage, but with image_type 'avatar'.
|
|
53
|
+
const res = await client.im.v1.image.create({
|
|
54
|
+
data: { image_type: 'avatar', image: Buffer.from(AVATAR_PNG_BASE64, 'base64') },
|
|
55
|
+
});
|
|
56
|
+
const imageKey = res?.image_key;
|
|
57
|
+
if (!imageKey)
|
|
58
|
+
throw new Error(`no image_key in response (${JSON.stringify(res)})`);
|
|
59
|
+
cache.imageKey = imageKey;
|
|
60
|
+
saveCache(larkAppId, cache);
|
|
61
|
+
logger.info(`[session-avatar] uploaded avatar for ${larkAppId} → ${imageKey}`);
|
|
62
|
+
return imageKey;
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
logger.warn(`[session-avatar] avatar upload failed: ${err}`);
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Apply the session-group avatar to a freshly-born group. Fire-and-forget —
|
|
71
|
+
* never throws; a failure just leaves the default Feishu group avatar.
|
|
72
|
+
*/
|
|
73
|
+
export async function applySessionGroupAvatar(larkAppId, chatId) {
|
|
74
|
+
try {
|
|
75
|
+
const cfg = getBot(larkAppId).config;
|
|
76
|
+
if (cfg.sessionGroup?.avatar === 'off')
|
|
77
|
+
return;
|
|
78
|
+
const imageKey = await ensureAvatarImageKey(larkAppId);
|
|
79
|
+
if (!imageKey)
|
|
80
|
+
return;
|
|
81
|
+
const client = getBotClient(larkAppId);
|
|
82
|
+
const res = await client.im.v1.chat.update({
|
|
83
|
+
path: { chat_id: chatId },
|
|
84
|
+
data: { avatar: imageKey },
|
|
85
|
+
});
|
|
86
|
+
if (res?.code !== 0 && res?.code !== undefined) {
|
|
87
|
+
logger.warn(`[session-avatar] chat.update avatar failed for ${chatId.substring(0, 12)}: ${res?.msg} (code ${res?.code})`);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
logger.info(`[session-avatar] applied to ${chatId.substring(0, 12)}`);
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
logger.warn(`[session-avatar] applying to ${chatId.substring(0, 12)} threw: ${err}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=session-group-avatar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-group-avatar.js","sourceRoot":"","sources":["../../src/services/session-group-avatar.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Child env for the one-shot title call — the SAME security boundary as every
|
|
3
|
+
* other CLI child the daemon spawns (PR review P2): `redactChildEnv` strips
|
|
4
|
+
* daemon-only secrets (LARK_APP_SECRET, GITHUB_TOKEN, tmux client vars, Claude
|
|
5
|
+
* session markers) and `sanitizePerBotEnv(cfg.env)` layers the bot's own
|
|
6
|
+
* provider environment (base URL / auth token) on top so multi-provider bots
|
|
7
|
+
* title through their own account instead of the daemon's. Exported for the
|
|
8
|
+
* env-boundary regression tests.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Resolve the one-shot launch with the SAME launcher semantics as the formal
|
|
12
|
+
* CLI spawn path (PR review): `wrapperCli` goes through buildWrappedLaunch —
|
|
13
|
+
* the shared builder that knows the gateway specifics (ttadk needs
|
|
14
|
+
* `-m <model> --skip-check` or it opens an interactive model selector /
|
|
15
|
+
* preflight and a non-TTY execFile hangs to timeout; aiden strips args it
|
|
16
|
+
* rejects; cjadk rewrites codex config args) — plus wrapperLaunchEnv for the
|
|
17
|
+
* wrapper's non-interactive env knobs (CJADK_INTERACTIVE=0). Without a
|
|
18
|
+
* wrapper, `cliPathOverride` (registerBot enforces it as an exact shadow of
|
|
19
|
+
* cliRuntime.executable, so runtime configs are covered transitively)
|
|
20
|
+
* replaces the template bin; otherwise the template runs verbatim. Exported
|
|
21
|
+
* for tests.
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveOneShotCommand(cfg: {
|
|
24
|
+
wrapperCli?: string;
|
|
25
|
+
cliPathOverride?: string;
|
|
26
|
+
model?: string;
|
|
27
|
+
}, template: readonly string[]): {
|
|
28
|
+
argv: string[];
|
|
29
|
+
env?: Record<string, string>;
|
|
30
|
+
};
|
|
31
|
+
export declare function buildOneShotEnv(botEnv: unknown): NodeJS.ProcessEnv;
|
|
32
|
+
export declare function buildTitlePrompt(text: string, maxLen: number, locale: string): string;
|
|
33
|
+
/** Extract a plausible title from one-shot CLI stdout: last non-empty line
|
|
34
|
+
* (codex/opencode prepend progress logs; claude/gemini print the bare
|
|
35
|
+
* answer), stripped of quotes/markdown and length-capped. Two passes: a
|
|
36
|
+
* strict pass drops known log-line shapes; if that filters EVERYTHING (an
|
|
37
|
+
* output shape we didn't predict), a lenient pass takes the last line that
|
|
38
|
+
* still looks like prose — never let over-filtering blank a real answer. */
|
|
39
|
+
export declare function sanitizeTitleOutput(stdout: string, maxLen: number): string | null;
|
|
40
|
+
/** Fire-and-forget: generate an AI title for a freshly-born session group and
|
|
41
|
+
* rename the chat (+ session record) when it lands. */
|
|
42
|
+
export declare function scheduleSessionGroupTitle(opts: {
|
|
43
|
+
larkAppId: string;
|
|
44
|
+
chatId: string;
|
|
45
|
+
userText: string;
|
|
46
|
+
}): void;
|
|
47
|
+
//# sourceMappingURL=session-group-title.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-group-title.d.ts","sourceRoot":"","sources":["../../src/services/session-group-title.ts"],"names":[],"mappings":"AA8CA;;;;;;;;GAQG;AACH;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,EACtE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CASlD;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,UAAU,CASlE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAMrF;AAYD;;;;;6EAK6E;AAC7E,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAuBjF;AAED;wDACwD;AACxD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,IAAI,CAuFP"}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Async AI title for session groups (p2pMode='group', naming.mode='ai-summary').
|
|
3
|
+
*
|
|
4
|
+
* Two-phase naming: the group is created instantly with a truncated
|
|
5
|
+
* placeholder name; this module then runs ONE headless single-turn call
|
|
6
|
+
* through the bot's own CLI to produce a short title and renames the chat
|
|
7
|
+
* when it lands. Fire-and-forget — every failure path simply keeps the
|
|
8
|
+
* placeholder, never blocks or breaks the conversation.
|
|
9
|
+
*
|
|
10
|
+
* The one-shot command is a small per-cliId argv template (print/exec modes
|
|
11
|
+
* of the CLIs botmux already drives). CLIs without a known print mode
|
|
12
|
+
* degrade to the placeholder silently.
|
|
13
|
+
*/
|
|
14
|
+
import { execFile } from 'node:child_process';
|
|
15
|
+
import { tmpdir } from 'node:os';
|
|
16
|
+
import { getBot } from '../bot-registry.js';
|
|
17
|
+
import { redactChildEnv } from '../utils/child-env.js';
|
|
18
|
+
import { sanitizePerBotEnv } from '../core/per-bot-env.js';
|
|
19
|
+
import { buildWrappedLaunch, wrapperLaunchEnv } from '../setup/cli-selection.js';
|
|
20
|
+
import { renameChat } from './groups-store.js';
|
|
21
|
+
import { getSessionGroup, markSessionGroupTitled, touchSessionGroup } from './session-groups-store.js';
|
|
22
|
+
import * as sessionStore from './session-store.js';
|
|
23
|
+
import { updateSessionTitle } from '../core/session-title.js';
|
|
24
|
+
import { localeForBot } from '../i18n/index.js';
|
|
25
|
+
import { logger } from '../utils/logger.js';
|
|
26
|
+
// Generous: one-shot CLIs pay cold-start + API latency (codex regularly
|
|
27
|
+
// exceeds 15s); the rename is async so a slow title costs nothing visible.
|
|
28
|
+
const TITLE_TIMEOUT_MS = 45_000;
|
|
29
|
+
const DEFAULT_MAX_LEN = 12;
|
|
30
|
+
/** Per-cliId one-shot print-mode argv template. `argv[0]` is replaced by
|
|
31
|
+
* `cliPathOverride` when configured. Prompt is appended as the last arg. */
|
|
32
|
+
const ONE_SHOT_ARGV = {
|
|
33
|
+
'claude-code': ['claude', '-p'],
|
|
34
|
+
codex: ['codex', 'exec', '--skip-git-repo-check'],
|
|
35
|
+
// TRAE CLI is a codex fork — same exec surface and bare-answer stdout.
|
|
36
|
+
traex: ['traex', 'exec', '--skip-git-repo-check'],
|
|
37
|
+
opencode: ['opencode', 'run'],
|
|
38
|
+
gemini: ['gemini', '-p'],
|
|
39
|
+
};
|
|
40
|
+
/** One in-flight title job per chat — birth and the heal-on-activity path
|
|
41
|
+
* (handleThreadReply) can otherwise race duplicate CLI calls. */
|
|
42
|
+
const inFlightTitles = new Set();
|
|
43
|
+
/**
|
|
44
|
+
* Child env for the one-shot title call — the SAME security boundary as every
|
|
45
|
+
* other CLI child the daemon spawns (PR review P2): `redactChildEnv` strips
|
|
46
|
+
* daemon-only secrets (LARK_APP_SECRET, GITHUB_TOKEN, tmux client vars, Claude
|
|
47
|
+
* session markers) and `sanitizePerBotEnv(cfg.env)` layers the bot's own
|
|
48
|
+
* provider environment (base URL / auth token) on top so multi-provider bots
|
|
49
|
+
* title through their own account instead of the daemon's. Exported for the
|
|
50
|
+
* env-boundary regression tests.
|
|
51
|
+
*/
|
|
52
|
+
/**
|
|
53
|
+
* Resolve the one-shot launch with the SAME launcher semantics as the formal
|
|
54
|
+
* CLI spawn path (PR review): `wrapperCli` goes through buildWrappedLaunch —
|
|
55
|
+
* the shared builder that knows the gateway specifics (ttadk needs
|
|
56
|
+
* `-m <model> --skip-check` or it opens an interactive model selector /
|
|
57
|
+
* preflight and a non-TTY execFile hangs to timeout; aiden strips args it
|
|
58
|
+
* rejects; cjadk rewrites codex config args) — plus wrapperLaunchEnv for the
|
|
59
|
+
* wrapper's non-interactive env knobs (CJADK_INTERACTIVE=0). Without a
|
|
60
|
+
* wrapper, `cliPathOverride` (registerBot enforces it as an exact shadow of
|
|
61
|
+
* cliRuntime.executable, so runtime configs are covered transitively)
|
|
62
|
+
* replaces the template bin; otherwise the template runs verbatim. Exported
|
|
63
|
+
* for tests.
|
|
64
|
+
*/
|
|
65
|
+
export function resolveOneShotCommand(cfg, template) {
|
|
66
|
+
const wrapper = cfg.wrapperCli?.trim();
|
|
67
|
+
if (wrapper) {
|
|
68
|
+
const { bin, args } = buildWrappedLaunch(wrapper, template.slice(1), b => b, { ttadkModel: cfg.model });
|
|
69
|
+
return { argv: [bin, ...args], env: wrapperLaunchEnv(wrapper) };
|
|
70
|
+
}
|
|
71
|
+
const override = cfg.cliPathOverride?.trim();
|
|
72
|
+
if (override)
|
|
73
|
+
return { argv: [override, ...template.slice(1)] };
|
|
74
|
+
return { argv: [...template] };
|
|
75
|
+
}
|
|
76
|
+
export function buildOneShotEnv(botEnv) {
|
|
77
|
+
const env = {
|
|
78
|
+
...redactChildEnv(process.env),
|
|
79
|
+
...sanitizePerBotEnv(botEnv),
|
|
80
|
+
};
|
|
81
|
+
// Never let the one-shot inherit a botmux session identity (redundant with
|
|
82
|
+
// the marker scrub above, kept as an explicit invariant).
|
|
83
|
+
delete env.BOTMUX_SESSION_ID;
|
|
84
|
+
return env;
|
|
85
|
+
}
|
|
86
|
+
export function buildTitlePrompt(text, maxLen, locale) {
|
|
87
|
+
const excerpt = text.replace(/\s+/g, ' ').trim().slice(0, 500);
|
|
88
|
+
if (locale === 'en') {
|
|
89
|
+
return `Summarize the following request as a conversation title of at most ${maxLen} characters. Output ONLY the title itself — no quotes, no trailing period, no explanation:\n\n${excerpt}`;
|
|
90
|
+
}
|
|
91
|
+
return `用不超过${maxLen}个字总结下面这条请求,作为会话标题。只输出标题本身,不要引号、句号或任何解释:\n\n${excerpt}`;
|
|
92
|
+
}
|
|
93
|
+
/** Strip decoration from a candidate title line. */
|
|
94
|
+
function cleanTitleLine(raw) {
|
|
95
|
+
return raw
|
|
96
|
+
.replace(/^["'“”‘’`#*\s]+/, '')
|
|
97
|
+
// Trailing quotes/backticks and sentence punctuation interleave (e.g.
|
|
98
|
+
// `标题"。`) — strip them as one class so the order can't matter.
|
|
99
|
+
.replace(/["'“”‘’`。.!!??\s]+$/, '')
|
|
100
|
+
.trim();
|
|
101
|
+
}
|
|
102
|
+
/** Extract a plausible title from one-shot CLI stdout: last non-empty line
|
|
103
|
+
* (codex/opencode prepend progress logs; claude/gemini print the bare
|
|
104
|
+
* answer), stripped of quotes/markdown and length-capped. Two passes: a
|
|
105
|
+
* strict pass drops known log-line shapes; if that filters EVERYTHING (an
|
|
106
|
+
* output shape we didn't predict), a lenient pass takes the last line that
|
|
107
|
+
* still looks like prose — never let over-filtering blank a real answer. */
|
|
108
|
+
export function sanitizeTitleOutput(stdout, maxLen) {
|
|
109
|
+
const all = stdout.split('\n').map(l => l.trim()).filter(Boolean);
|
|
110
|
+
// Obvious non-answers in ANY pass: dividers, bare numbers, hook chatter,
|
|
111
|
+
// lines with no letter/digit at all.
|
|
112
|
+
const junk = (l) => !/[\p{L}\p{N}]/u.test(l) || /^[-=—_\s]+$/.test(l) || /^\d[\d,.\s]*$/.test(l) || /^hook:/i.test(l);
|
|
113
|
+
const strict = all
|
|
114
|
+
// codex exec progress lines look like "[2026-08-05T…] tokens used: 123" —
|
|
115
|
+
// drop bracketed/log-ish lines so the answer line survives as the last one.
|
|
116
|
+
.filter(l => !junk(l) && !/^\[.*\]/.test(l) && !/^(tokens used|thinking|codex$|user$)/i.test(l));
|
|
117
|
+
// Lenient fallback: keep anything prose-like, including bracket-prefixed
|
|
118
|
+
// lines the strict pass dropped (unpredicted "[ts] answer" shapes).
|
|
119
|
+
const lenient = all.filter(l => !junk(l));
|
|
120
|
+
const raw = strict.length ? strict[strict.length - 1]
|
|
121
|
+
// The lenient pick may still carry a bracketed log prefix — strip it so a
|
|
122
|
+
// "[ts] answer" line yields the answer, not the timestamp.
|
|
123
|
+
: lenient.length ? lenient[lenient.length - 1].replace(/^\[[^\]]*\]\s*/, '') : '';
|
|
124
|
+
const cleaned = cleanTitleLine(raw);
|
|
125
|
+
if (!cleaned)
|
|
126
|
+
return null;
|
|
127
|
+
// Hard cap: maxLen is advisory to the model; enforce a generous ceiling so
|
|
128
|
+
// a slightly-long but good title still beats the placeholder.
|
|
129
|
+
const capped = Array.from(cleaned).slice(0, Math.max(maxLen * 2, 16)).join('');
|
|
130
|
+
return capped || null;
|
|
131
|
+
}
|
|
132
|
+
/** Fire-and-forget: generate an AI title for a freshly-born session group and
|
|
133
|
+
* rename the chat (+ session record) when it lands. */
|
|
134
|
+
export function scheduleSessionGroupTitle(opts) {
|
|
135
|
+
const { larkAppId, chatId, userText } = opts;
|
|
136
|
+
if (inFlightTitles.has(chatId))
|
|
137
|
+
return;
|
|
138
|
+
inFlightTitles.add(chatId);
|
|
139
|
+
void (async () => {
|
|
140
|
+
try {
|
|
141
|
+
const cfg = getBot(larkAppId).config;
|
|
142
|
+
const sg = cfg.sessionGroup ?? {};
|
|
143
|
+
if ((sg.naming?.mode ?? 'ai-summary') !== 'ai-summary')
|
|
144
|
+
return;
|
|
145
|
+
if (!userText.trim())
|
|
146
|
+
return;
|
|
147
|
+
const maxLen = sg.naming?.maxLen && sg.naming.maxLen > 0 ? sg.naming.maxLen : DEFAULT_MAX_LEN;
|
|
148
|
+
const template = ONE_SHOT_ARGV[cfg.cliId];
|
|
149
|
+
if (!template) {
|
|
150
|
+
logger.info(`[session-group] no one-shot template for cliId=${cfg.cliId}; keeping placeholder title`);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const { argv, env: wrapperEnv } = resolveOneShotCommand(cfg, template);
|
|
154
|
+
const prompt = buildTitlePrompt(userText, maxLen, localeForBot(larkAppId));
|
|
155
|
+
const runOnce = () => new Promise((resolve, reject) => {
|
|
156
|
+
const env = { ...buildOneShotEnv(cfg.env), ...wrapperEnv };
|
|
157
|
+
const child = execFile(argv[0], [...argv.slice(1), prompt], {
|
|
158
|
+
timeout: TITLE_TIMEOUT_MS,
|
|
159
|
+
maxBuffer: 1024 * 1024,
|
|
160
|
+
cwd: tmpdir(),
|
|
161
|
+
env,
|
|
162
|
+
}, (err, out, errOut) => {
|
|
163
|
+
if (err && !out) {
|
|
164
|
+
// Surface stderr — execFile's bare "Command failed: …" hides the
|
|
165
|
+
// actual CLI error (API failures, auth, rate limits).
|
|
166
|
+
const detail = String(errOut ?? '').trim().split('\n').slice(-2).join(' ').slice(0, 200);
|
|
167
|
+
return reject(new Error(`${err.message.split('\n')[0]}${detail ? ` | stderr: ${detail}` : ''}`));
|
|
168
|
+
}
|
|
169
|
+
resolve(String(out ?? ''));
|
|
170
|
+
});
|
|
171
|
+
// CRITICAL: close stdin. codex-family CLIs (codex/traex) treat a piped
|
|
172
|
+
// stdin as "additional input" and BLOCK reading it until EOF — with
|
|
173
|
+
// execFile's default open pipe they hang to the timeout and get killed
|
|
174
|
+
// ("Reading additional input from stdin..."). A TTY stdin (manual
|
|
175
|
+
// testing) skips that path, which is why this only bites under the
|
|
176
|
+
// daemon. Closing stdin is a no-op for CLIs that never read it.
|
|
177
|
+
child.stdin?.end();
|
|
178
|
+
});
|
|
179
|
+
// One-shot CLI calls fail transiently (API hiccups, cold start races) —
|
|
180
|
+
// a single spaced retry recovers most of them without delaying much.
|
|
181
|
+
let stdout;
|
|
182
|
+
try {
|
|
183
|
+
stdout = await runOnce();
|
|
184
|
+
}
|
|
185
|
+
catch (firstErr) {
|
|
186
|
+
logger.info(`[session-group] AI title attempt 1 failed for chat=${chatId.substring(0, 12)} (retrying): ${firstErr}`);
|
|
187
|
+
await new Promise(r => setTimeout(r, 3000));
|
|
188
|
+
stdout = await runOnce();
|
|
189
|
+
}
|
|
190
|
+
const title = sanitizeTitleOutput(stdout, maxLen);
|
|
191
|
+
if (!title) {
|
|
192
|
+
// Log the raw head — an unpredicted output shape is invisible otherwise.
|
|
193
|
+
const rawHead = stdout.replace(/\s+/g, ' ').trim().slice(0, 200);
|
|
194
|
+
logger.info(`[session-group] AI title empty for chat=${chatId.substring(0, 12)}; keeping placeholder (raw: "${rawHead}")`);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const prefix = sg.namePrefix ?? '';
|
|
198
|
+
const finalName = `${prefix}${title}`;
|
|
199
|
+
// Reuse the shared renameChat wrapper (membership precheck + error
|
|
200
|
+
// classification) instead of a bespoke chat.update call.
|
|
201
|
+
const r = await renameChat(larkAppId, chatId, finalName);
|
|
202
|
+
if (!r.ok) {
|
|
203
|
+
logger.warn(`[session-group] rename chat=${chatId.substring(0, 12)} failed: ${r.error}${r.detail ? ` (${r.detail})` : ''}`);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
markSessionGroupTitled(chatId);
|
|
207
|
+
// Best-effort: keep the botmux session title in sync so `botmux list` /
|
|
208
|
+
// dashboard show the same name as the chat (same path as /rename).
|
|
209
|
+
const entry = getSessionGroup(chatId);
|
|
210
|
+
if (entry?.lastSessionId) {
|
|
211
|
+
const session = sessionStore.getSession(entry.lastSessionId);
|
|
212
|
+
if (session)
|
|
213
|
+
updateSessionTitle(session, title, 'system');
|
|
214
|
+
touchSessionGroup(chatId);
|
|
215
|
+
}
|
|
216
|
+
logger.info(`[session-group] titled chat=${chatId.substring(0, 12)} "${finalName}"`);
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
logger.info(`[session-group] AI title failed for chat=${chatId.substring(0, 12)} (placeholder kept): ${err}`);
|
|
220
|
+
}
|
|
221
|
+
finally {
|
|
222
|
+
inFlightTitles.delete(chatId);
|
|
223
|
+
}
|
|
224
|
+
})();
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=session-group-title.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-group-title.js","sourceRoot":"","sources":["../../src/services/session-group-title.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface SessionGroupEntry {
|
|
2
|
+
/** The DM user this group was born for (open_id in the bot's app scope). */
|
|
3
|
+
ownerOpenId: string;
|
|
4
|
+
/** Most recent session anchored in this group; same-group resume target. */
|
|
5
|
+
lastSessionId: string;
|
|
6
|
+
/** Epoch ms the group was created. */
|
|
7
|
+
createdAt: number;
|
|
8
|
+
/** Epoch ms of the last observed activity (birth, resume, new session). */
|
|
9
|
+
lastActiveAt: number;
|
|
10
|
+
/** True once the async AI title has been applied to the chat name. */
|
|
11
|
+
titled?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare function initSessionGroups(appId: string): void;
|
|
14
|
+
/** Register a freshly-born session group (or overwrite after a re-birth). */
|
|
15
|
+
export declare function registerSessionGroup(chatId: string, entry: Omit<SessionGroupEntry, 'createdAt' | 'lastActiveAt'> & {
|
|
16
|
+
createdAt?: number;
|
|
17
|
+
}): void;
|
|
18
|
+
/** Typing check — the ONLY sanctioned way to tell a session group apart. */
|
|
19
|
+
export declare function isSessionGroup(chatId: string): boolean;
|
|
20
|
+
export declare function getSessionGroup(chatId: string): SessionGroupEntry | undefined;
|
|
21
|
+
/** Point the registry at the session currently living in this group. */
|
|
22
|
+
export declare function touchSessionGroup(chatId: string, lastSessionId?: string): void;
|
|
23
|
+
/** Mark the async AI title as applied (idempotent). */
|
|
24
|
+
export declare function markSessionGroupTitled(chatId: string): void;
|
|
25
|
+
/** Remove a registry entry (group disbanded / bot removed / gc). */
|
|
26
|
+
export declare function removeSessionGroup(chatId: string): void;
|
|
27
|
+
export declare function listSessionGroups(): Array<{
|
|
28
|
+
chatId: string;
|
|
29
|
+
} & SessionGroupEntry>;
|
|
30
|
+
//# sourceMappingURL=session-groups-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-groups-store.d.ts","sourceRoot":"","sources":["../../src/services/session-groups-store.ts"],"names":[],"mappings":"AA2BA,MAAM,WAAW,iBAAiB;IAChC,4EAA4E;IAC5E,WAAW,EAAE,MAAM,CAAC;IACpB,4EAA4E;IAC5E,aAAa,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,YAAY,EAAE,MAAM,CAAC;IACrB,sEAAsE;IACtE,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAMD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAIrD;AAyCD,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,iBAAiB,EAAE,WAAW,GAAG,cAAc,CAAC,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAWhJ;AAED,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAItD;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAI7E;AAED,wEAAwE;AACxE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAO9E;AAED,uDAAuD;AACvD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAM3D;AAED,oEAAoE;AACpE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAGvD;AAED,wBAAgB,iBAAiB,IAAI,KAAK,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,iBAAiB,CAAC,CAIjF"}
|