{"configuration":{},"description":"Description","documentation":{},"id":9,"lastModifiedAgent":"structurizr-ui","lastModifiedDate":"2026-02-24T08:46:21Z","lastModifiedUser":"zdfd","model":{"people":[{"description":"A broadcaster's audience member who participates in conversations, answers questions, and writes comments.","id":"1","name":"User","properties":{"structurizr.dsl.identifier":"user"},"relationships":[{"description":"Participates in conversations, writes comments, answers questions","destinationId":"12","id":"50","sourceId":"1","tags":"Relationship"},{"description":"Visits broadcaster website","destinationId":"37","id":"51","sourceId":"1","tags":"Relationship"}],"tags":"Element,Person,user"},{"description":"Reviews and moderates user-generated content. Manages conversations via the moderation dashboard.","id":"2","name":"Moderator","properties":{"structurizr.dsl.identifier":"moderator"},"relationships":[{"description":"Moderates content via moderation dashboard","destinationId":"12","id":"52","sourceId":"2","tags":"Relationship"}],"tags":"Element,Person,user,owned"},{"description":"Creates questions and topics, manages editorial content, configures feature templates.","id":"3","name":"Editor","properties":{"structurizr.dsl.identifier":"editor"},"relationships":[{"description":"Creates and manages conversations via editorial dashboard","destinationId":"12","id":"53","sourceId":"3","tags":"Relationship"},{"description":"Publishes editorial content","destinationId":"39","id":"54","sourceId":"3","tags":"Relationship"},{"description":"Publishes editorial content","destinationId":"37","id":"55","linkedRelationshipId":"54","sourceId":"3"}],"tags":"Element,Person,user,owned"},{"description":"A partner developer who integrates PSI into a broadcaster's website or contributes open modules.","id":"4","name":"Developer","properties":{"structurizr.dsl.identifier":"developer"},"relationships":[{"description":"Develops features and integrations","destinationId":"12","id":"56","sourceId":"4","tags":"Relationship"},{"description":"Tests PSI integration on publisher sites","destinationId":"46","id":"57","sourceId":"4","tags":"Relationship"}],"tags":"Element,Person,user,developer"}],"softwareSystems":[{"description":"Large language model API used for AI pre-moderation (two-pass: light model + heavy model), ranking, name checking, and translation.","documentation":{},"id":"5","name":"OpenAI","properties":{"structurizr.dsl.identifier":"openai"},"tags":"Element,Software System,external"},{"description":"Jigsaw Perspective API for toxicity scoring of user-generated content.","documentation":{},"id":"6","name":"Google Perspective API","properties":{"structurizr.dsl.identifier":"perspective_api"},"tags":"Element,Software System,external"},{"description":"Transactional email delivery. Supports Postmark, SendGrid, or SMTP.","documentation":{},"id":"7","name":"Email Service","properties":{"structurizr.dsl.identifier":"email_service"},"tags":"Element,Software System,external"},{"description":"Error monitoring and performance tracking for both client and server.","documentation":{},"id":"8","name":"Sentry","properties":{"structurizr.dsl.identifier":"sentry"},"tags":"Element,Software System,external"},{"description":"Analytics data warehouse for event logging and dashboard data ingestion.","documentation":{},"id":"9","name":"Google BigQuery","properties":{"structurizr.dsl.identifier":"bigquery"},"tags":"Element,Software System,external"},{"description":"Machine translation via DeepL, TextShuttle, or SRG SSR enterprise API for multi-language comment translation.","documentation":{},"id":"10","name":"Translation Service","properties":{"structurizr.dsl.identifier":"translation_service"},"tags":"Element,Software System,external"},{"description":"Structured logging for server-side events. Feeds into BigQuery via log sinks for analytics pipelines.","documentation":{},"id":"11","name":"Google Cloud Logging","properties":{"structurizr.dsl.identifier":"google_cloud_logging"},"tags":"Element,Software System,external"},{"containers":[{"components":[{"description":"18 structure definitions (16 core + 2 ZDF): Question, Profile, Article, Topic, Admin, Login, Editorial Dash, Moderation Dash, Account, Settings, Simple Comments, Developer Tools, Component Demo, Test Structure, plus ZDF Mod Dashboard and Video Voting.","documentation":{},"id":"14","name":"Structures","properties":{"structurizr.dsl.identifier":"psi.frontend.structures"},"relationships":[{"description":"Reads instance data via hooks","destinationId":"17","id":"139","sourceId":"14","tags":"Relationship"},{"description":"Uses shared UI components","destinationId":"16","id":"142","sourceId":"14","tags":"Relationship"},{"description":"Displays translated strings via t() function","destinationId":"21","id":"144","sourceId":"14","tags":"Relationship"}],"tags":"Element,Component","technology":"TypeScript, React"},{"description":"60+ feature plugins that extend structures via config slots (widgets, callbacks, data). Core ~25 features, ZDF 23, CBC/RC 8, SRG 3. E.g. comment-slider, reactions, moderation, pin-comment, representing-perspectives.","documentation":{},"id":"15","name":"Features","properties":{"structurizr.dsl.identifier":"psi.frontend.features"},"relationships":[{"description":"Reads and writes data via hooks and callbacks","destinationId":"17","id":"140","sourceId":"15","tags":"Relationship"},{"description":"Extends via config slots (widgets, callbacks, data)","destinationId":"14","id":"141","sourceId":"15","tags":"Relationship"},{"description":"Uses shared UI components","destinationId":"16","id":"143","sourceId":"15","tags":"Relationship"},{"description":"Displays translated strings via t() function","destinationId":"21","id":"145","sourceId":"15","tags":"Relationship"}],"tags":"Element,Component","technology":"TypeScript, React"},{"description":"50+ reusable UI components based on the PSI Design System Figma. Uses IBM Plex fonts and Carbon Icons.","documentation":{},"id":"16","name":"Design System Components","properties":{"structurizr.dsl.identifier":"psi.frontend.design_system"},"tags":"Element,Component","technology":"TypeScript, React Native"},{"description":"Client-side scoped data access. Enforces instance isolation. Provides useCollection, useObject, useModuleData hooks.","documentation":{},"id":"17","name":"Datastore","properties":{"structurizr.dsl.identifier":"psi.frontend.client_datastore"},"relationships":[{"description":"Delegates data operations","destinationId":"19","id":"146","sourceId":"17","tags":"Relationship"}],"tags":"Element,Component","technology":"TypeScript, React Context"},{"description":"Client-side auth adapter. Wraps Firebase Auth SDK for Google sign-in, custom token sign-in (SSO), and auth state management. Noop adapter for testing.","documentation":{},"id":"18","name":"Auth Adapter","properties":{"structurizr.dsl.identifier":"psi.frontend.client_auth_adapter"},"relationships":[{"description":"Firebase Auth SDK","destinationId":"36","id":"149","sourceId":"18","tags":"Relationship"}],"tags":"Element,Component","technology":"Firebase Auth SDK"},{"description":"Client-side database adapter. Implementations: FirebaseDatabaseAdapter (direct WebSocket), ServerDatabaseAdapter (all data via REST API, used by SRG silo), DemoDatabaseAdapter (in-memory for demos).","documentation":{},"id":"19","name":"Database Adapter","properties":{"structurizr.dsl.identifier":"psi.frontend.client_db_adapter"},"relationships":[{"description":"Firebase direct connection","destinationId":"33","id":"147","sourceId":"19","tags":"Relationship"},{"description":"Server-proxied data access (ServerDatabaseAdapter)","destinationId":"22","id":"148","sourceId":"19","tags":"Relationship"}],"tags":"Element,Component","technology":"Firebase SDK / fetch"},{"description":"Partner-contributed client code: ZDF (moderation dash, video voting, articles, channels, conversation helper, 23 features), CBC/RC (8 features), SRG (3 features).","documentation":{},"id":"20","name":"Partner Open Modules","properties":{"structurizr.dsl.identifier":"psi.frontend.client_open_modules"},"relationships":[{"description":"Extends core structures","destinationId":"14","id":"150","sourceId":"20","tags":"Relationship"},{"description":"Adds partner-specific features","destinationId":"15","id":"151","sourceId":"20","tags":"Relationship"},{"description":"Uses data access APIs","destinationId":"17","id":"152","sourceId":"20","tags":"Relationship"}],"tags":"Element,Component","technology":"TypeScript, React"},{"description":"Internationalization system supporting English, French (multiple variants), German, Italian, Dutch, Romansh. Human + machine translations. Silo-level string overrides.","documentation":{},"id":"21","name":"Translations","properties":{"structurizr.dsl.identifier":"psi.frontend.translations"},"tags":"Element,Component","technology":"TypeScript, JSON"}],"description":"Expo SDK 54 client application providing the UI for conversations, moderation, profiles, and editorial tools. Uses expo-router for file-system routing.","documentation":{},"id":"13","name":"PSI Frontend","properties":{"structurizr.dsl.identifier":"psi.frontend"},"relationships":[{"description":"API calls via HTTPS (/api/*)","destinationId":"22","id":"73","sourceId":"13","tags":"Relationship","technology":"REST/JSON"},{"description":"API calls via HTTPS (/api/*) [alternative deployment]","destinationId":"32","id":"74","sourceId":"13","tags":"Relationship","technology":"REST/JSON"},{"description":"Sign-in (Google, custom token)","destinationId":"36","id":"75","sourceId":"13","tags":"Relationship","technology":"Firebase SDK"},{"description":"Reads real-time data [direct mode]","destinationId":"33","id":"76","sourceId":"13","tags":"Relationship","technology":"Firebase SDK"},{"description":"Uploads user files","destinationId":"35","id":"77","sourceId":"13","tags":"Relationship","technology":"Firebase SDK"},{"description":"Redirects user for SSO login","destinationId":"41","id":"92","sourceId":"13","tags":"Relationship","technology":"OIDC"},{"description":"Redirects user for SSO login","destinationId":"40","id":"93","linkedRelationshipId":"92","sourceId":"13","technology":"OIDC"}],"tags":"Element,Container,WebBrowser","technology":"TypeScript, React Native for Web, Expo"},{"components":[{"description":"Path-based routing: /:moduleId/:apiId and /api/:moduleId/:apiId. Authenticates requests, creates scoped ServerStore, dispatches to module public/admin functions.","documentation":{},"id":"23","name":"API Router","properties":{"structurizr.dsl.identifier":"psi.backend_firebase.api_router"},"relationships":[{"description":"Authenticates incoming requests","destinationId":"24","id":"116","sourceId":"23","tags":"Relationship"},{"description":"Creates scoped ServerStore per request","destinationId":"29","id":"117","sourceId":"23","tags":"Relationship"},{"description":"Dispatches to module public/admin functions","destinationId":"30","id":"118","sourceId":"23","tags":"Relationship"},{"description":"Dispatches to partner module functions","destinationId":"31","id":"119","sourceId":"23","tags":"Relationship"}],"tags":"Element,Component","technology":"Hono middleware"},{"description":"Adapter interface for authentication. Verifies Firebase ID tokens, manages sessions via better-auth, creates custom tokens for SSO. Plugins: firebaseIdToken, genericOidc.","documentation":{},"id":"24","name":"Auth Adapter","properties":{"structurizr.dsl.identifier":"psi.backend_firebase.auth_adapter"},"relationships":[{"description":"Verifies Firebase ID tokens","destinationId":"36","id":"121","sourceId":"24","tags":"Relationship"},{"description":"Fetches JWKS for JWT verification","destinationId":"41","id":"122","sourceId":"24","tags":"Relationship"},{"description":"Fetches JWKS for JWT verification","destinationId":"40","id":"123","linkedRelationshipId":"122","sourceId":"24"}],"tags":"Element,Component","technology":"better-auth, Firebase Admin"},{"description":"Adapter interface abstracting data storage. Implementations for Firebase RTDB and MongoDB. Selected via DATABASE_ADAPTER env var.","documentation":{},"id":"25","name":"Database Adapter","properties":{"structurizr.dsl.identifier":"psi.backend_firebase.db_adapter"},"relationships":[{"description":"Firebase RTDB implementation","destinationId":"33","id":"126","sourceId":"25","tags":"Relationship"},{"description":"MongoDB implementation","destinationId":"34","id":"127","sourceId":"25","tags":"Relationship"}],"tags":"Element,Component","technology":"Firebase Admin / MongoDB driver"},{"description":"Adapter interface for sending emails. Implementations for Postmark, SendGrid, and SMTP. Selected via EMAIL_PROVIDER env var.","documentation":{},"id":"26","name":"Email Adapter","properties":{"structurizr.dsl.identifier":"psi.backend_firebase.email_adapter"},"relationships":[{"description":"Sends emails via configured provider","destinationId":"7","id":"128","sourceId":"26","tags":"Relationship"}],"tags":"Element,Component","technology":"Postmark / SendGrid / Nodemailer"},{"description":"Adapter interface for AI services. Used for pre-moderation (two-pass), ranking, name checking, and content analysis. Selected via OPENAI_PROVIDER env var.","documentation":{},"id":"27","name":"LLM Adapter","properties":{"structurizr.dsl.identifier":"psi.backend_firebase.llm_adapter"},"relationships":[{"description":"Calls OpenAI/Azure OpenAI","destinationId":"5","id":"129","sourceId":"27","tags":"Relationship"},{"description":"Calls Perspective API","destinationId":"6","id":"130","sourceId":"27","tags":"Relationship"}],"tags":"Element,Component","technology":"OpenAI / Azure OpenAI / Perspective API"},{"description":"Adapter interface for multi-language content translation. Implementations for LLM (OpenAI), DeepL, TextShuttle, and SRG SSR enterprise API. Selected via TEXT_TRANSLATION_PROVIDER env var.","documentation":{},"id":"28","name":"Translation Adapter","properties":{"structurizr.dsl.identifier":"psi.backend_firebase.translation_adapter"},"relationships":[{"description":"Translates via DeepL/TextShuttle/SRG SSR","destinationId":"10","id":"131","sourceId":"28","tags":"Relationship"},{"description":"Translates via GPT (LLM adapter mode)","destinationId":"5","id":"132","sourceId":"28","tags":"Relationship"}],"tags":"Element,Component","technology":"OpenAI / DeepL / TextShuttle / SRG SSR"},{"description":"Scoped data access layer. Enforces instance and module isolation. Batches writes until API function completes. Supports data modes: PRIVATE, PUBLIC, USER_GLOBAL, USER_READ_GLOBAL.","documentation":{},"id":"29","name":"ServerStore","properties":{"structurizr.dsl.identifier":"psi.backend_firebase.server_store"},"relationships":[{"description":"Reads and writes data through adapter","destinationId":"25","id":"120","sourceId":"29","tags":"Relationship"}],"tags":"Element,Component","technology":"TypeScript"},{"description":"24 server modules: admin, analytics, article, auth, contentTranslation, database, debug, derivedviews, devlogin, global, health, jigsaw, language, moderation, notifs, premodReview, profile, puppet, questions, ranking, suspension, topics, users, constructor.","documentation":{},"id":"30","name":"Core Server Modules","properties":{"structurizr.dsl.identifier":"psi.backend_firebase.core_modules"},"relationships":[{"description":"Data access via scoped store","destinationId":"29","id":"133","sourceId":"30","tags":"Relationship"},{"description":"AI moderation and ranking calls","destinationId":"27","id":"134","sourceId":"30","tags":"Relationship"},{"description":"Sends notification emails","destinationId":"26","id":"135","sourceId":"30","tags":"Relationship"},{"description":"Content translation calls","destinationId":"28","id":"136","sourceId":"30","tags":"Relationship"}],"tags":"Element,Component","technology":"TypeScript"},{"description":"Partner-contributed server modules: ZDF (article-teaser-position, blocklist, channel, conversation-helper, moderation, push-notifications, videovoting), CBC/RC (topicmigration).","documentation":{},"id":"31","name":"Partner Open Modules","properties":{"structurizr.dsl.identifier":"psi.backend_firebase.partner_modules"},"relationships":[{"description":"Data access via scoped store","destinationId":"29","id":"137","sourceId":"31","tags":"Relationship"},{"description":"AI calls (conversation helper, etc.)","destinationId":"27","id":"138","sourceId":"31","tags":"Relationship"}],"tags":"Element,Component","technology":"TypeScript"}],"description":"Serverless API hosted as Firebase Cloud Functions. Handles auth, CRUD operations, moderation dispatch, and module API routing via Hono.","documentation":{},"id":"22","name":"PSI Backend (Cloud Functions)","properties":{"structurizr.dsl.identifier":"psi.backend_firebase"},"relationships":[{"description":"Reads and writes silo/instance data","destinationId":"33","id":"78","sourceId":"22","tags":"Relationship","technology":"Firebase Admin SDK"},{"description":"Reads and writes data [alternative]","destinationId":"34","id":"79","sourceId":"22","tags":"Relationship","technology":"MongoDB driver"},{"description":"Verifies tokens, creates users","destinationId":"36","id":"80","sourceId":"22","tags":"Relationship","technology":"Firebase Admin SDK"},{"description":"Manages stored files","destinationId":"35","id":"81","sourceId":"22","tags":"Relationship","technology":"Firebase Admin SDK"},{"description":"POST /v1/chat/completions","destinationId":"5","id":"85","sourceId":"22","tags":"Relationship","technology":"HTTPS"},{"description":"POST /v1alpha1/comments:analyze","destinationId":"6","id":"86","sourceId":"22","tags":"Relationship","technology":"HTTPS"},{"description":"Send transactional emails","destinationId":"7","id":"87","sourceId":"22","tags":"Relationship","technology":"HTTPS"},{"description":"Error reports","destinationId":"8","id":"88","sourceId":"22","tags":"Relationship","technology":"HTTPS"},{"description":"Stream event logs","destinationId":"9","id":"89","sourceId":"22","tags":"Relationship","technology":"HTTPS"},{"description":"Translate text","destinationId":"10","id":"90","sourceId":"22","tags":"Relationship","technology":"HTTPS"},{"description":"Structured logs","destinationId":"11","id":"91","sourceId":"22","tags":"Relationship","technology":"HTTPS"},{"description":"Fetches JWKS for JWT verification","destinationId":"41","id":"124","linkedRelationshipId":"122","sourceId":"22"},{"description":"Fetches JWKS for JWT verification","destinationId":"40","id":"125","linkedRelationshipId":"122","sourceId":"22"}],"tags":"Element,Container,ms","technology":"TypeScript, Hono, Firebase Functions"},{"description":"Containerized standalone API server. Same codebase as Cloud Functions, deployed as Docker container with @hono/node-server.","documentation":{},"id":"32","name":"PSI Backend (Standalone)","properties":{"structurizr.dsl.identifier":"psi.backend_express"},"relationships":[{"description":"Reads and writes silo/instance data","destinationId":"33","id":"82","sourceId":"32","tags":"Relationship","technology":"Firebase Admin SDK"},{"description":"Reads and writes data [alternative]","destinationId":"34","id":"83","sourceId":"32","tags":"Relationship","technology":"MongoDB driver"},{"description":"Verifies tokens, creates users","destinationId":"36","id":"84","sourceId":"32","tags":"Relationship","technology":"Firebase Admin SDK"}],"tags":"Element,Container,ms,alternative","technology":"TypeScript, Hono, Node.js 22"},{"description":"Primary data store. Stores silo data, instance collections, module data, and user profiles.","documentation":{},"id":"33","name":"Firebase Realtime Database","properties":{"structurizr.dsl.identifier":"psi.firebase_rtdb"},"tags":"Element,Container,Database","technology":"Firebase RTDB"},{"description":"Alternative database backend via adapter pattern. Stores same data model using compound-prefixed keys.","documentation":{},"id":"34","name":"MongoDB","properties":{"structurizr.dsl.identifier":"psi.mongodb"},"tags":"Element,Container,Database,alternative","technology":"MongoDB 6+"},{"description":"Stores user-uploaded files such as profile images.","documentation":{},"id":"35","name":"Firebase Storage","properties":{"structurizr.dsl.identifier":"psi.firebase_storage"},"tags":"Element,Container,Database","technology":"Firebase Storage"},{"description":"Manages user authentication state, custom tokens for SSO, and Google sign-in.","documentation":{},"id":"36","name":"Firebase Auth","properties":{"structurizr.dsl.identifier":"psi.firebase_auth"},"tags":"Element,Container,ms","technology":"Firebase Auth"}],"description":"The core Public Spaces Incubator platform. A modular toolkit for creating pro-social conversation spaces, built with a plugin architecture of Structures and Features.","documentation":{},"id":"12","name":"PSI System","properties":{"structurizr.dsl.identifier":"psi"},"relationships":[{"description":"Authenticates users, stores data, hosts application","destinationId":"49","id":"58","sourceId":"12","tags":"Relationship"},{"description":"Delegates SSO authentication via OIDC","destinationId":"40","id":"59","sourceId":"12","tags":"Relationship"},{"description":"Sends comments for AI pre-moderation, ranking, translation","destinationId":"5","id":"60","sourceId":"12","tags":"Relationship"},{"description":"Scores content toxicity","destinationId":"6","id":"61","sourceId":"12","tags":"Relationship"},{"description":"Sends notification and verification emails","destinationId":"7","id":"62","sourceId":"12","tags":"Relationship"},{"description":"Reports errors and performance data","destinationId":"8","id":"63","sourceId":"12","tags":"Relationship"},{"description":"Streams event logs for analytics","destinationId":"9","id":"64","sourceId":"12","tags":"Relationship"},{"description":"Translates comments between languages","destinationId":"10","id":"65","sourceId":"12","tags":"Relationship"},{"description":"Structured event logging","destinationId":"11","id":"66","sourceId":"12","tags":"Relationship"},{"description":"Redirects user for SSO login","destinationId":"41","id":"94","linkedRelationshipId":"92","sourceId":"12","technology":"OIDC"}],"tags":"Element,Software System,owned"},{"containers":[{"description":"The broadcaster's existing web application (e.g. heute.de, radio-canada.ca, rts.ch) into which PSI is embedded via iframes or script injection.","documentation":{},"id":"38","name":"Publisher Website","properties":{"structurizr.dsl.identifier":"broadcaster.broadcaster_frontend"},"relationships":[{"description":"Embeds PSI sidebar and teasers via iframes","destinationId":"13","id":"100","sourceId":"38","tags":"Relationship","technology":"HTML/JS"},{"description":"Embeds PSI sidebar and teasers via iframes","destinationId":"12","id":"101","linkedRelationshipId":"100","sourceId":"38","technology":"HTML/JS"}],"tags":"Element,Container,WebBrowser,foreign","technology":"Various (publisher's tech stack)"},{"description":"The broadcaster's CMS that manages articles, videos, and other content. PSI conversations can be linked to specific content items via article URLs.","documentation":{},"id":"39","name":"Content Management System","properties":{"structurizr.dsl.identifier":"broadcaster.broadcaster_cms"},"relationships":[{"description":"Publishes content","destinationId":"38","id":"99","sourceId":"39","tags":"Relationship"}],"tags":"Element,Container,foreign","technology":"Various"}],"description":"A public media broadcaster's existing web platform (e.g. heute.de, radio-canada.ca, rts.ch) into which PSI conversations are embedded.","documentation":{},"id":"37","name":"Broadcaster System","properties":{"structurizr.dsl.identifier":"broadcaster"},"relationships":[{"description":"Embeds PSI conversations via iframes and scripts","destinationId":"12","id":"67","sourceId":"37","tags":"Relationship"},{"description":"Embeds PSI sidebar and teasers via iframes","destinationId":"13","id":"102","linkedRelationshipId":"100","sourceId":"37","technology":"HTML/JS"}],"tags":"Element,Software System,foreign"},{"containers":[{"description":"OpenID Connect identity provider. Can be Keycloak (ZDF), CBC/RC IdP, or any OIDC-compliant provider. Exposes authorization and JWKS endpoints.","documentation":{},"id":"41","name":"OIDC Provider","properties":{"structurizr.dsl.identifier":"identity_provider.idp_app"},"relationships":[{"description":"Returns ID token after authentication","destinationId":"13","id":"95","sourceId":"41","tags":"Relationship","technology":"OIDC redirect"},{"description":"Returns ID token after authentication","destinationId":"12","id":"96","linkedRelationshipId":"95","sourceId":"41","technology":"OIDC redirect"}],"tags":"Element,Container,ms,foreign","technology":"Keycloak / Custom OIDC"}],"description":"OpenID Connect identity provider for Single Sign-On. Supports Keycloak (ZDF), Azure AD B2C (CBC/RC), RTBF Login, KRO-NCRV/NPO ID, SRG SSR Account, and Google.","documentation":{},"id":"40","name":"Identity Provider","properties":{"structurizr.dsl.identifier":"identity_provider"},"relationships":[{"description":"Returns ID token after authentication","destinationId":"13","id":"97","linkedRelationshipId":"95","sourceId":"40","technology":"OIDC redirect"},{"description":"Returns ID token after authentication","destinationId":"12","id":"98","linkedRelationshipId":"95","sourceId":"40","technology":"OIDC redirect"}],"tags":"Element,Software System,foreign"},{"containers":[{"description":"Standalone Express server implementing the moderation pipeline. Two-pass system: light model for initial screening, heavy model for flagged content. Includes blocklist management.","documentation":{},"id":"43","name":"Moderation Service API","properties":{"structurizr.dsl.identifier":"moderation.moderation_api"},"relationships":[{"description":"Two-pass moderation: light model then heavy model","destinationId":"5","id":"109","sourceId":"43","tags":"Relationship","technology":"HTTPS"},{"description":"Toxicity scoring","destinationId":"6","id":"110","sourceId":"43","tags":"Relationship","technology":"HTTPS"},{"description":"Stores moderation decisions and blocklist","destinationId":"44","id":"111","sourceId":"43","tags":"Relationship","technology":"Firebase Admin SDK"},{"description":"Stores data [alternative]","destinationId":"45","id":"112","sourceId":"43","tags":"Relationship","technology":"MongoDB driver"},{"description":"Error reports","destinationId":"8","id":"113","sourceId":"43","tags":"Relationship","technology":"HTTPS"},{"description":"Sends moderation notification emails","destinationId":"7","id":"114","sourceId":"43","tags":"Relationship","technology":"HTTPS"}],"tags":"Element,Container,ms","technology":"TypeScript, Express 4, Node.js"},{"description":"Primary data store for moderation decisions, blocklist entries, and review queue.","documentation":{},"id":"44","name":"Firebase Firestore","properties":{"structurizr.dsl.identifier":"moderation.moderation_firestore"},"tags":"Element,Container,Database","technology":"Firebase Firestore"},{"description":"Alternative database backend for the moderation service. Selected via DATABASE_ADAPTER env var.","documentation":{},"id":"45","name":"MongoDB","properties":{"structurizr.dsl.identifier":"moderation.moderation_mongodb"},"tags":"Element,Container,Database,alternative","technology":"MongoDB 7"}],"description":"Standalone microservice for automated content moderation. Integrates with OpenAI and Perspective API for two-pass AI screening. Includes blocklist management.","documentation":{},"id":"42","name":"Moderation Service","properties":{"structurizr.dsl.identifier":"moderation"},"relationships":[{"description":"Calls LLM for content moderation decisions","destinationId":"5","id":"68","sourceId":"42","tags":"Relationship"},{"description":"Scores content toxicity","destinationId":"6","id":"69","sourceId":"42","tags":"Relationship"},{"description":"Reports errors","destinationId":"8","id":"70","sourceId":"42","tags":"Relationship"},{"description":"Sends moderation notification emails","destinationId":"7","id":"115","linkedRelationshipId":"114","sourceId":"42","technology":"HTTPS"}],"tags":"Element,Software System,owned"},{"containers":[{"description":"Reverse proxy that rewrites publisher web pages to inject the psi.js script, enabling sidebar and teaser iframes on any publisher site.","documentation":{},"id":"47","name":"Content Proxy (Demo Proxy)","properties":{"structurizr.dsl.identifier":"publisher_integration.demo_proxy"},"relationships":[{"description":"Proxies and injects psi.js script","destinationId":"38","id":"103","sourceId":"47","tags":"Relationship","technology":"HTTP reverse proxy"},{"description":"Proxies and injects psi.js script","destinationId":"37","id":"104","linkedRelationshipId":"103","sourceId":"47","technology":"HTTP reverse proxy"}],"tags":"Element,Container,ms","technology":"Node.js"},{"description":"Next.js example application demonstrating how partners integrate PSI teasers and sidebar into their sites using server-side React.","documentation":{},"id":"48","name":"Publisher Demo","properties":{"structurizr.dsl.identifier":"publisher_integration.publisher_demo"},"relationships":[{"description":"Fetches question metadata for teasers","destinationId":"22","id":"106","sourceId":"48","tags":"Relationship","technology":"REST/JSON"},{"description":"Fetches question metadata for teasers","destinationId":"12","id":"107","linkedRelationshipId":"106","sourceId":"48","technology":"REST/JSON"}],"tags":"Element,Container,WebBrowser","technology":"Next.js 14, TypeScript"}],"description":"Tools for demonstrating and integrating PSI into broadcaster websites. Includes a content proxy and a Next.js demo application.","documentation":{},"id":"46","name":"Publisher Integration Tools","properties":{"structurizr.dsl.identifier":"publisher_integration"},"relationships":[{"description":"Demonstrates PSI embedding","destinationId":"12","id":"71","sourceId":"46","tags":"Relationship"},{"description":"Proxies and rewrites broadcaster pages","destinationId":"37","id":"72","sourceId":"46","tags":"Relationship"},{"description":"Proxies and injects psi.js script","destinationId":"38","id":"105","linkedRelationshipId":"103","sourceId":"46","technology":"HTTP reverse proxy"},{"description":"Fetches question metadata for teasers","destinationId":"22","id":"108","linkedRelationshipId":"106","sourceId":"46","technology":"REST/JSON"}],"tags":"Element,Software System,owned"},{"description":"Google Firebase services providing authentication, realtime database, cloud functions hosting, file storage, Firestore, and static hosting.","documentation":{},"id":"49","name":"Firebase Platform","properties":{"structurizr.dsl.identifier":"firebase"},"tags":"Element,Software System,Google Cloud Platform"}]},"name":"PSI - Public Spaces Incubator Architecture","properties":{"structurizr.inspection.info":"0","structurizr.inspection.ignore":"0","structurizr.inspection.error":"74","structurizr.inspection.warning":"0","structurizr.dsl":"d29ya3NwYWNlICJQU0kgLSBQdWJsaWMgU3BhY2VzIEluY3ViYXRvciBBcmNoaXRlY3R1cmUiIHsKCiAgICAhaWRlbnRpZmllcnMgaGllcmFyY2hpY2FsCgogICAgbW9kZWwgewogICAgICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQogICAgICAgIC8vIFBlb3BsZQogICAgICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQogICAgICAgIHVzZXIgPSBwZXJzb24gIlVzZXIiICJBIGJyb2FkY2FzdGVyJ3MgYXVkaWVuY2UgbWVtYmVyIHdobyBwYXJ0aWNpcGF0ZXMgaW4gY29udmVyc2F0aW9ucywgYW5zd2VycyBxdWVzdGlvbnMsIGFuZCB3cml0ZXMgY29tbWVudHMuIiAidXNlciIKICAgICAgICBtb2RlcmF0b3IgPSBwZXJzb24gIk1vZGVyYXRvciIgIlJldmlld3MgYW5kIG1vZGVyYXRlcyB1c2VyLWdlbmVyYXRlZCBjb250ZW50LiBNYW5hZ2VzIGNvbnZlcnNhdGlvbnMgdmlhIHRoZSBtb2RlcmF0aW9uIGRhc2hib2FyZC4iICJ1c2VyLCBvd25lZCIKICAgICAgICBlZGl0b3IgPSBwZXJzb24gIkVkaXRvciIgIkNyZWF0ZXMgcXVlc3Rpb25zIGFuZCB0b3BpY3MsIG1hbmFnZXMgZWRpdG9yaWFsIGNvbnRlbnQsIGNvbmZpZ3VyZXMgZmVhdHVyZSB0ZW1wbGF0ZXMuIiAidXNlciwgb3duZWQiCiAgICAgICAgZGV2ZWxvcGVyID0gcGVyc29uICJEZXZlbG9wZXIiICJBIHBhcnRuZXIgZGV2ZWxvcGVyIHdobyBpbnRlZ3JhdGVzIFBTSSBpbnRvIGEgYnJvYWRjYXN0ZXIncyB3ZWJzaXRlIG9yIGNvbnRyaWJ1dGVzIG9wZW4gbW9kdWxlcy4iICJ1c2VyLCBkZXZlbG9wZXIiCgogICAgICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQogICAgICAgIC8vIEV4dGVybmFsIFN5c3RlbXMKICAgICAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KICAgICAgICBvcGVuYWkgPSBzb2Z0d2FyZVN5c3RlbSAiT3BlbkFJIiAiTGFyZ2UgbGFuZ3VhZ2UgbW9kZWwgQVBJIHVzZWQgZm9yIEFJIHByZS1tb2RlcmF0aW9uICh0d28tcGFzczogbGlnaHQgbW9kZWwgKyBoZWF2eSBtb2RlbCksIHJhbmtpbmcsIG5hbWUgY2hlY2tpbmcsIGFuZCB0cmFuc2xhdGlvbi4iICJleHRlcm5hbCIKICAgICAgICBwZXJzcGVjdGl2ZV9hcGkgPSBzb2Z0d2FyZVN5c3RlbSAiR29vZ2xlIFBlcnNwZWN0aXZlIEFQSSIgIkppZ3NhdyBQZXJzcGVjdGl2ZSBBUEkgZm9yIHRveGljaXR5IHNjb3Jpbmcgb2YgdXNlci1nZW5lcmF0ZWQgY29udGVudC4iICJleHRlcm5hbCIKICAgICAgICBlbWFpbF9zZXJ2aWNlID0gc29mdHdhcmVTeXN0ZW0gIkVtYWlsIFNlcnZpY2UiICJUcmFuc2FjdGlvbmFsIGVtYWlsIGRlbGl2ZXJ5LiBTdXBwb3J0cyBQb3N0bWFyaywgU2VuZEdyaWQsIG9yIFNNVFAuIiAiZXh0ZXJuYWwiCiAgICAgICAgc2VudHJ5ID0gc29mdHdhcmVTeXN0ZW0gIlNlbnRyeSIgIkVycm9yIG1vbml0b3JpbmcgYW5kIHBlcmZvcm1hbmNlIHRyYWNraW5nIGZvciBib3RoIGNsaWVudCBhbmQgc2VydmVyLiIgImV4dGVybmFsIgogICAgICAgIGJpZ3F1ZXJ5ID0gc29mdHdhcmVTeXN0ZW0gIkdvb2dsZSBCaWdRdWVyeSIgIkFuYWx5dGljcyBkYXRhIHdhcmVob3VzZSBmb3IgZXZlbnQgbG9nZ2luZyBhbmQgZGFzaGJvYXJkIGRhdGEgaW5nZXN0aW9uLiIgImV4dGVybmFsIgogICAgICAgIHRyYW5zbGF0aW9uX3NlcnZpY2UgPSBzb2Z0d2FyZVN5c3RlbSAiVHJhbnNsYXRpb24gU2VydmljZSIgIk1hY2hpbmUgdHJhbnNsYXRpb24gdmlhIERlZXBMLCBUZXh0U2h1dHRsZSwgb3IgU1JHIFNTUiBlbnRlcnByaXNlIEFQSSBmb3IgbXVsdGktbGFuZ3VhZ2UgY29tbWVudCB0cmFuc2xhdGlvbi4iICJleHRlcm5hbCIKICAgICAgICBnb29nbGVfY2xvdWRfbG9nZ2luZyA9IHNvZnR3YXJlU3lzdGVtICJHb29nbGUgQ2xvdWQgTG9nZ2luZyIgIlN0cnVjdHVyZWQgbG9nZ2luZyBmb3Igc2VydmVyLXNpZGUgZXZlbnRzLiBGZWVkcyBpbnRvIEJpZ1F1ZXJ5IHZpYSBsb2cgc2lua3MgZm9yIGFuYWx5dGljcyBwaXBlbGluZXMuIiAiZXh0ZXJuYWwiCgogICAgICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQogICAgICAgIC8vIFNvZnR3YXJlIFN5c3RlbXMKICAgICAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCiAgICAgICAgLy8gLS0tIFBTSSBTeXN0ZW0gLS0tCiAgICAgICAgcHNpID0gc29mdHdhcmVTeXN0ZW0gIlBTSSBTeXN0ZW0iICJUaGUgY29yZSBQdWJsaWMgU3BhY2VzIEluY3ViYXRvciBwbGF0Zm9ybS4gQSBtb2R1bGFyIHRvb2xraXQgZm9yIGNyZWF0aW5nIHByby1zb2NpYWwgY29udmVyc2F0aW9uIHNwYWNlcywgYnVpbHQgd2l0aCBhIHBsdWdpbiBhcmNoaXRlY3R1cmUgb2YgU3RydWN0dXJlcyBhbmQgRmVhdHVyZXMuIiAib3duZWQiIHsKCiAgICAgICAgICAgIC8vIC0tLSBQU0kgRnJvbnRlbmQgKHdpdGggY29tcG9uZW50cykgLS0tCiAgICAgICAgICAgIGZyb250ZW5kID0gY29udGFpbmVyICJQU0kgRnJvbnRlbmQiICJFeHBvIFNESyA1NCBjbGllbnQgYXBwbGljYXRpb24gcHJvdmlkaW5nIHRoZSBVSSBmb3IgY29udmVyc2F0aW9ucywgbW9kZXJhdGlvbiwgcHJvZmlsZXMsIGFuZCBlZGl0b3JpYWwgdG9vbHMuIFVzZXMgZXhwby1yb3V0ZXIgZm9yIGZpbGUtc3lzdGVtIHJvdXRpbmcuIiAiVHlwZVNjcmlwdCwgUmVhY3QgTmF0aXZlIGZvciBXZWIsIEV4cG8iICJXZWJCcm93c2VyIiB7CiAgICAgICAgICAgICAgICBzdHJ1Y3R1cmVzID0gY29tcG9uZW50ICJTdHJ1Y3R1cmVzIiAiMTggc3RydWN0dXJlIGRlZmluaXRpb25zICgxNiBjb3JlICsgMiBaREYpOiBRdWVzdGlvbiwgUHJvZmlsZSwgQXJ0aWNsZSwgVG9waWMsIEFkbWluLCBMb2dpbiwgRWRpdG9yaWFsIERhc2gsIE1vZGVyYXRpb24gRGFzaCwgQWNjb3VudCwgU2V0dGluZ3MsIFNpbXBsZSBDb21tZW50cywgRGV2ZWxvcGVyIFRvb2xzLCBDb21wb25lbnQgRGVtbywgVGVzdCBTdHJ1Y3R1cmUsIHBsdXMgWkRGIE1vZCBEYXNoYm9hcmQgYW5kIFZpZGVvIFZvdGluZy4iICJUeXBlU2NyaXB0LCBSZWFjdCIKICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gY29tcG9uZW50ICJGZWF0dXJlcyIgIjYwKyBmZWF0dXJlIHBsdWdpbnMgdGhhdCBleHRlbmQgc3RydWN0dXJlcyB2aWEgY29uZmlnIHNsb3RzICh3aWRnZXRzLCBjYWxsYmFja3MsIGRhdGEpLiBDb3JlIH4yNSBmZWF0dXJlcywgWkRGIDIzLCBDQkMvUkMgOCwgU1JHIDMuIEUuZy4gY29tbWVudC1zbGlkZXIsIHJlYWN0aW9ucywgbW9kZXJhdGlvbiwgcGluLWNvbW1lbnQsIHJlcHJlc2VudGluZy1wZXJzcGVjdGl2ZXMuIiAiVHlwZVNjcmlwdCwgUmVhY3QiCiAgICAgICAgICAgICAgICBkZXNpZ25fc3lzdGVtID0gY29tcG9uZW50ICJEZXNpZ24gU3lzdGVtIENvbXBvbmVudHMiICI1MCsgcmV1c2FibGUgVUkgY29tcG9uZW50cyBiYXNlZCBvbiB0aGUgUFNJIERlc2lnbiBTeXN0ZW0gRmlnbWEuIFVzZXMgSUJNIFBsZXggZm9udHMgYW5kIENhcmJvbiBJY29ucy4iICJUeXBlU2NyaXB0LCBSZWFjdCBOYXRpdmUiCiAgICAgICAgICAgICAgICBjbGllbnRfZGF0YXN0b3JlID0gY29tcG9uZW50ICJEYXRhc3RvcmUiICJDbGllbnQtc2lkZSBzY29wZWQgZGF0YSBhY2Nlc3MuIEVuZm9yY2VzIGluc3RhbmNlIGlzb2xhdGlvbi4gUHJvdmlkZXMgdXNlQ29sbGVjdGlvbiwgdXNlT2JqZWN0LCB1c2VNb2R1bGVEYXRhIGhvb2tzLiIgIlR5cGVTY3JpcHQsIFJlYWN0IENvbnRleHQiCiAgICAgICAgICAgICAgICBjbGllbnRfYXV0aF9hZGFwdGVyID0gY29tcG9uZW50ICJBdXRoIEFkYXB0ZXIiICJDbGllbnQtc2lkZSBhdXRoIGFkYXB0ZXIuIFdyYXBzIEZpcmViYXNlIEF1dGggU0RLIGZvciBHb29nbGUgc2lnbi1pbiwgY3VzdG9tIHRva2VuIHNpZ24taW4gKFNTTyksIGFuZCBhdXRoIHN0YXRlIG1hbmFnZW1lbnQuIE5vb3AgYWRhcHRlciBmb3IgdGVzdGluZy4iICJGaXJlYmFzZSBBdXRoIFNESyIKICAgICAgICAgICAgICAgIGNsaWVudF9kYl9hZGFwdGVyID0gY29tcG9uZW50ICJEYXRhYmFzZSBBZGFwdGVyIiAiQ2xpZW50LXNpZGUgZGF0YWJhc2UgYWRhcHRlci4gSW1wbGVtZW50YXRpb25zOiBGaXJlYmFzZURhdGFiYXNlQWRhcHRlciAoZGlyZWN0IFdlYlNvY2tldCksIFNlcnZlckRhdGFiYXNlQWRhcHRlciAoYWxsIGRhdGEgdmlhIFJFU1QgQVBJLCB1c2VkIGJ5IFNSRyBzaWxvKSwgRGVtb0RhdGFiYXNlQWRhcHRlciAoaW4tbWVtb3J5IGZvciBkZW1vcykuIiAiRmlyZWJhc2UgU0RLIC8gZmV0Y2giCiAgICAgICAgICAgICAgICBjbGllbnRfb3Blbl9tb2R1bGVzID0gY29tcG9uZW50ICJQYXJ0bmVyIE9wZW4gTW9kdWxlcyIgIlBhcnRuZXItY29udHJpYnV0ZWQgY2xpZW50IGNvZGU6IFpERiAobW9kZXJhdGlvbiBkYXNoLCB2aWRlbyB2b3RpbmcsIGFydGljbGVzLCBjaGFubmVscywgY29udmVyc2F0aW9uIGhlbHBlciwgMjMgZmVhdHVyZXMpLCBDQkMvUkMgKDggZmVhdHVyZXMpLCBTUkcgKDMgZmVhdHVyZXMpLiIgIlR5cGVTY3JpcHQsIFJlYWN0IgogICAgICAgICAgICAgICAgdHJhbnNsYXRpb25zID0gY29tcG9uZW50ICJUcmFuc2xhdGlvbnMiICJJbnRlcm5hdGlvbmFsaXphdGlvbiBzeXN0ZW0gc3VwcG9ydGluZyBFbmdsaXNoLCBGcmVuY2ggKG11bHRpcGxlIHZhcmlhbnRzKSwgR2VybWFuLCBJdGFsaWFuLCBEdXRjaCwgUm9tYW5zaC4gSHVtYW4gKyBtYWNoaW5lIHRyYW5zbGF0aW9ucy4gU2lsby1sZXZlbCBzdHJpbmcgb3ZlcnJpZGVzLiIgIlR5cGVTY3JpcHQsIEpTT04iCiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIC8vIC0tLSBQU0kgQmFja2VuZCBDbG91ZCBGdW5jdGlvbnMgKHdpdGggY29tcG9uZW50cykgLS0tCiAgICAgICAgICAgIGJhY2tlbmRfZmlyZWJhc2UgPSBjb250YWluZXIgIlBTSSBCYWNrZW5kIChDbG91ZCBGdW5jdGlvbnMpIiAiU2VydmVybGVzcyBBUEkgaG9zdGVkIGFzIEZpcmViYXNlIENsb3VkIEZ1bmN0aW9ucy4gSGFuZGxlcyBhdXRoLCBDUlVEIG9wZXJhdGlvbnMsIG1vZGVyYXRpb24gZGlzcGF0Y2gsIGFuZCBtb2R1bGUgQVBJIHJvdXRpbmcgdmlhIEhvbm8uIiAiVHlwZVNjcmlwdCwgSG9ubywgRmlyZWJhc2UgRnVuY3Rpb25zIiAibXMiIHsKICAgICAgICAgICAgICAgIGFwaV9yb3V0ZXIgPSBjb21wb25lbnQgIkFQSSBSb3V0ZXIiICJQYXRoLWJhc2VkIHJvdXRpbmc6IC86bW9kdWxlSWQvOmFwaUlkIGFuZCAvYXBpLzptb2R1bGVJZC86YXBpSWQuIEF1dGhlbnRpY2F0ZXMgcmVxdWVzdHMsIGNyZWF0ZXMgc2NvcGVkIFNlcnZlclN0b3JlLCBkaXNwYXRjaGVzIHRvIG1vZHVsZSBwdWJsaWMvYWRtaW4gZnVuY3Rpb25zLiIgIkhvbm8gbWlkZGxld2FyZSIKICAgICAgICAgICAgICAgIGF1dGhfYWRhcHRlciA9IGNvbXBvbmVudCAiQXV0aCBBZGFwdGVyIiAiQWRhcHRlciBpbnRlcmZhY2UgZm9yIGF1dGhlbnRpY2F0aW9uLiBWZXJpZmllcyBGaXJlYmFzZSBJRCB0b2tlbnMsIG1hbmFnZXMgc2Vzc2lvbnMgdmlhIGJldHRlci1hdXRoLCBjcmVhdGVzIGN1c3RvbSB0b2tlbnMgZm9yIFNTTy4gUGx1Z2luczogZmlyZWJhc2VJZFRva2VuLCBnZW5lcmljT2lkYy4iICJiZXR0ZXItYXV0aCwgRmlyZWJhc2UgQWRtaW4iCiAgICAgICAgICAgICAgICBkYl9hZGFwdGVyID0gY29tcG9uZW50ICJEYXRhYmFzZSBBZGFwdGVyIiAiQWRhcHRlciBpbnRlcmZhY2UgYWJzdHJhY3RpbmcgZGF0YSBzdG9yYWdlLiBJbXBsZW1lbnRhdGlvbnMgZm9yIEZpcmViYXNlIFJUREIgYW5kIE1vbmdvREIuIFNlbGVjdGVkIHZpYSBEQVRBQkFTRV9BREFQVEVSIGVudiB2YXIuIiAiRmlyZWJhc2UgQWRtaW4gLyBNb25nb0RCIGRyaXZlciIKICAgICAgICAgICAgICAgIGVtYWlsX2FkYXB0ZXIgPSBjb21wb25lbnQgIkVtYWlsIEFkYXB0ZXIiICJBZGFwdGVyIGludGVyZmFjZSBmb3Igc2VuZGluZyBlbWFpbHMuIEltcGxlbWVudGF0aW9ucyBmb3IgUG9zdG1hcmssIFNlbmRHcmlkLCBhbmQgU01UUC4gU2VsZWN0ZWQgdmlhIEVNQUlMX1BST1ZJREVSIGVudiB2YXIuIiAiUG9zdG1hcmsgLyBTZW5kR3JpZCAvIE5vZGVtYWlsZXIiCiAgICAgICAgICAgICAgICBsbG1fYWRhcHRlciA9IGNvbXBvbmVudCAiTExNIEFkYXB0ZXIiICJBZGFwdGVyIGludGVyZmFjZSBmb3IgQUkgc2VydmljZXMuIFVzZWQgZm9yIHByZS1tb2RlcmF0aW9uICh0d28tcGFzcyksIHJhbmtpbmcsIG5hbWUgY2hlY2tpbmcsIGFuZCBjb250ZW50IGFuYWx5c2lzLiBTZWxlY3RlZCB2aWEgT1BFTkFJX1BST1ZJREVSIGVudiB2YXIuIiAiT3BlbkFJIC8gQXp1cmUgT3BlbkFJIC8gUGVyc3BlY3RpdmUgQVBJIgogICAgICAgICAgICAgICAgdHJhbnNsYXRpb25fYWRhcHRlciA9IGNvbXBvbmVudCAiVHJhbnNsYXRpb24gQWRhcHRlciIgIkFkYXB0ZXIgaW50ZXJmYWNlIGZvciBtdWx0aS1sYW5ndWFnZSBjb250ZW50IHRyYW5zbGF0aW9uLiBJbXBsZW1lbnRhdGlvbnMgZm9yIExMTSAoT3BlbkFJKSwgRGVlcEwsIFRleHRTaHV0dGxlLCBhbmQgU1JHIFNTUiBlbnRlcnByaXNlIEFQSS4gU2VsZWN0ZWQgdmlhIFRFWFRfVFJBTlNMQVRJT05fUFJPVklERVIgZW52IHZhci4iICJPcGVuQUkgLyBEZWVwTCAvIFRleHRTaHV0dGxlIC8gU1JHIFNTUiIKICAgICAgICAgICAgICAgIHNlcnZlcl9zdG9yZSA9IGNvbXBvbmVudCAiU2VydmVyU3RvcmUiICJTY29wZWQgZGF0YSBhY2Nlc3MgbGF5ZXIuIEVuZm9yY2VzIGluc3RhbmNlIGFuZCBtb2R1bGUgaXNvbGF0aW9uLiBCYXRjaGVzIHdyaXRlcyB1bnRpbCBBUEkgZnVuY3Rpb24gY29tcGxldGVzLiBTdXBwb3J0cyBkYXRhIG1vZGVzOiBQUklWQVRFLCBQVUJMSUMsIFVTRVJfR0xPQkFMLCBVU0VSX1JFQURfR0xPQkFMLiIgIlR5cGVTY3JpcHQiCiAgICAgICAgICAgICAgICBjb3JlX21vZHVsZXMgPSBjb21wb25lbnQgIkNvcmUgU2VydmVyIE1vZHVsZXMiICIyNCBzZXJ2ZXIgbW9kdWxlczogYWRtaW4sIGFuYWx5dGljcywgYXJ0aWNsZSwgYXV0aCwgY29udGVudFRyYW5zbGF0aW9uLCBkYXRhYmFzZSwgZGVidWcsIGRlcml2ZWR2aWV3cywgZGV2bG9naW4sIGdsb2JhbCwgaGVhbHRoLCBqaWdzYXcsIGxhbmd1YWdlLCBtb2RlcmF0aW9uLCBub3RpZnMsIHByZW1vZFJldmlldywgcHJvZmlsZSwgcHVwcGV0LCBxdWVzdGlvbnMsIHJhbmtpbmcsIHN1c3BlbnNpb24sIHRvcGljcywgdXNlcnMsIGNvbnN0cnVjdG9yLiIgIlR5cGVTY3JpcHQiCiAgICAgICAgICAgICAgICBwYXJ0bmVyX21vZHVsZXMgPSBjb21wb25lbnQgIlBhcnRuZXIgT3BlbiBNb2R1bGVzIiAiUGFydG5lci1jb250cmlidXRlZCBzZXJ2ZXIgbW9kdWxlczogWkRGIChhcnRpY2xlLXRlYXNlci1wb3NpdGlvbiwgYmxvY2tsaXN0LCBjaGFubmVsLCBjb252ZXJzYXRpb24taGVscGVyLCBtb2RlcmF0aW9uLCBwdXNoLW5vdGlmaWNhdGlvbnMsIHZpZGVvdm90aW5nKSwgQ0JDL1JDICh0b3BpY21pZ3JhdGlvbikuIiAiVHlwZVNjcmlwdCIKICAgICAgICAgICAgfQoKICAgICAgICAgICAgLy8gLS0tIFBTSSBCYWNrZW5kIFN0YW5kYWxvbmUgKG5vIGNvbXBvbmVudHMgLSBzYW1lIGNvZGViYXNlIGFzIENsb3VkIEZ1bmN0aW9ucykgLS0tCiAgICAgICAgICAgIGJhY2tlbmRfZXhwcmVzcyA9IGNvbnRhaW5lciAiUFNJIEJhY2tlbmQgKFN0YW5kYWxvbmUpIiAiQ29udGFpbmVyaXplZCBzdGFuZGFsb25lIEFQSSBzZXJ2ZXIuIFNhbWUgY29kZWJhc2UgYXMgQ2xvdWQgRnVuY3Rpb25zLCBkZXBsb3llZCBhcyBEb2NrZXIgY29udGFpbmVyIHdpdGggQGhvbm8vbm9kZS1zZXJ2ZXIuIiAiVHlwZVNjcmlwdCwgSG9ubywgTm9kZS5qcyAyMiIgIm1zLCBhbHRlcm5hdGl2ZSIKCiAgICAgICAgICAgIC8vIC0tLSBEYXRhIHN0b3JlcyAtLS0KICAgICAgICAgICAgZmlyZWJhc2VfcnRkYiA9IGNvbnRhaW5lciAiRmlyZWJhc2UgUmVhbHRpbWUgRGF0YWJhc2UiICJQcmltYXJ5IGRhdGEgc3RvcmUuIFN0b3JlcyBzaWxvIGRhdGEsIGluc3RhbmNlIGNvbGxlY3Rpb25zLCBtb2R1bGUgZGF0YSwgYW5kIHVzZXIgcHJvZmlsZXMuIiAiRmlyZWJhc2UgUlREQiIgIkRhdGFiYXNlIgogICAgICAgICAgICBtb25nb2RiID0gY29udGFpbmVyICJNb25nb0RCIiAiQWx0ZXJuYXRpdmUgZGF0YWJhc2UgYmFja2VuZCB2aWEgYWRhcHRlciBwYXR0ZXJuLiBTdG9yZXMgc2FtZSBkYXRhIG1vZGVsIHVzaW5nIGNvbXBvdW5kLXByZWZpeGVkIGtleXMuIiAiTW9uZ29EQiA2KyIgIkRhdGFiYXNlLCBhbHRlcm5hdGl2ZSIKICAgICAgICAgICAgZmlyZWJhc2Vfc3RvcmFnZSA9IGNvbnRhaW5lciAiRmlyZWJhc2UgU3RvcmFnZSIgIlN0b3JlcyB1c2VyLXVwbG9hZGVkIGZpbGVzIHN1Y2ggYXMgcHJvZmlsZSBpbWFnZXMuIiAiRmlyZWJhc2UgU3RvcmFnZSIgIkRhdGFiYXNlIgogICAgICAgICAgICBmaXJlYmFzZV9hdXRoID0gY29udGFpbmVyICJGaXJlYmFzZSBBdXRoIiAiTWFuYWdlcyB1c2VyIGF1dGhlbnRpY2F0aW9uIHN0YXRlLCBjdXN0b20gdG9rZW5zIGZvciBTU08sIGFuZCBHb29nbGUgc2lnbi1pbi4iICJGaXJlYmFzZSBBdXRoIiAibXMiCiAgICAgICAgfQoKICAgICAgICAvLyAtLS0gQnJvYWRjYXN0ZXIgU3lzdGVtIC0tLQogICAgICAgIGJyb2FkY2FzdGVyID0gc29mdHdhcmVTeXN0ZW0gIkJyb2FkY2FzdGVyIFN5c3RlbSIgIkEgcHVibGljIG1lZGlhIGJyb2FkY2FzdGVyJ3MgZXhpc3Rpbmcgd2ViIHBsYXRmb3JtIChlLmcuIGhldXRlLmRlLCByYWRpby1jYW5hZGEuY2EsIHJ0cy5jaCkgaW50byB3aGljaCBQU0kgY29udmVyc2F0aW9ucyBhcmUgZW1iZWRkZWQuIiAiZm9yZWlnbiIgewogICAgICAgICAgICBicm9hZGNhc3Rlcl9mcm9udGVuZCA9IGNvbnRhaW5lciAiUHVibGlzaGVyIFdlYnNpdGUiICJUaGUgYnJvYWRjYXN0ZXIncyBleGlzdGluZyB3ZWIgYXBwbGljYXRpb24gKGUuZy4gaGV1dGUuZGUsIHJhZGlvLWNhbmFkYS5jYSwgcnRzLmNoKSBpbnRvIHdoaWNoIFBTSSBpcyBlbWJlZGRlZCB2aWEgaWZyYW1lcyBvciBzY3JpcHQgaW5qZWN0aW9uLiIgIlZhcmlvdXMgKHB1Ymxpc2hlcidzIHRlY2ggc3RhY2spIiAiV2ViQnJvd3NlciwgZm9yZWlnbiIKICAgICAgICAgICAgYnJvYWRjYXN0ZXJfY21zID0gY29udGFpbmVyICJDb250ZW50IE1hbmFnZW1lbnQgU3lzdGVtIiAiVGhlIGJyb2FkY2FzdGVyJ3MgQ01TIHRoYXQgbWFuYWdlcyBhcnRpY2xlcywgdmlkZW9zLCBhbmQgb3RoZXIgY29udGVudC4gUFNJIGNvbnZlcnNhdGlvbnMgY2FuIGJlIGxpbmtlZCB0byBzcGVjaWZpYyBjb250ZW50IGl0ZW1zIHZpYSBhcnRpY2xlIFVSTHMuIiAiVmFyaW91cyIgImZvcmVpZ24iCiAgICAgICAgfQoKICAgICAgICAvLyAtLS0gSWRlbnRpdHkgUHJvdmlkZXIgLS0tCiAgICAgICAgaWRlbnRpdHlfcHJvdmlkZXIgPSBzb2Z0d2FyZVN5c3RlbSAiSWRlbnRpdHkgUHJvdmlkZXIiICJPcGVuSUQgQ29ubmVjdCBpZGVudGl0eSBwcm92aWRlciBmb3IgU2luZ2xlIFNpZ24tT24uIFN1cHBvcnRzIEtleWNsb2FrIChaREYpLCBBenVyZSBBRCBCMkMgKENCQy9SQyksIFJUQkYgTG9naW4sIEtSTy1OQ1JWL05QTyBJRCwgU1JHIFNTUiBBY2NvdW50LCBhbmQgR29vZ2xlLiIgImZvcmVpZ24iIHsKICAgICAgICAgICAgaWRwX2FwcCA9IGNvbnRhaW5lciAiT0lEQyBQcm92aWRlciIgIk9wZW5JRCBDb25uZWN0IGlkZW50aXR5IHByb3ZpZGVyLiBDYW4gYmUgS2V5Y2xvYWsgKFpERiksIENCQy9SQyBJZFAsIG9yIGFueSBPSURDLWNvbXBsaWFudCBwcm92aWRlci4gRXhwb3NlcyBhdXRob3JpemF0aW9uIGFuZCBKV0tTIGVuZHBvaW50cy4iICJLZXljbG9hayAvIEN1c3RvbSBPSURDIiAibXMsIGZvcmVpZ24iCiAgICAgICAgfQoKICAgICAgICAvLyAtLS0gTW9kZXJhdGlvbiBTZXJ2aWNlIC0tLQogICAgICAgIG1vZGVyYXRpb24gPSBzb2Z0d2FyZVN5c3RlbSAiTW9kZXJhdGlvbiBTZXJ2aWNlIiAiU3RhbmRhbG9uZSBtaWNyb3NlcnZpY2UgZm9yIGF1dG9tYXRlZCBjb250ZW50IG1vZGVyYXRpb24uIEludGVncmF0ZXMgd2l0aCBPcGVuQUkgYW5kIFBlcnNwZWN0aXZlIEFQSSBmb3IgdHdvLXBhc3MgQUkgc2NyZWVuaW5nLiBJbmNsdWRlcyBibG9ja2xpc3QgbWFuYWdlbWVudC4iICJvd25lZCIgewogICAgICAgICAgICBtb2RlcmF0aW9uX2FwaSA9IGNvbnRhaW5lciAiTW9kZXJhdGlvbiBTZXJ2aWNlIEFQSSIgIlN0YW5kYWxvbmUgRXhwcmVzcyBzZXJ2ZXIgaW1wbGVtZW50aW5nIHRoZSBtb2RlcmF0aW9uIHBpcGVsaW5lLiBUd28tcGFzcyBzeXN0ZW06IGxpZ2h0IG1vZGVsIGZvciBpbml0aWFsIHNjcmVlbmluZywgaGVhdnkgbW9kZWwgZm9yIGZsYWdnZWQgY29udGVudC4gSW5jbHVkZXMgYmxvY2tsaXN0IG1hbmFnZW1lbnQuIiAiVHlwZVNjcmlwdCwgRXhwcmVzcyA0LCBOb2RlLmpzIiAibXMiCiAgICAgICAgICAgIG1vZGVyYXRpb25fZmlyZXN0b3JlID0gY29udGFpbmVyICJGaXJlYmFzZSBGaXJlc3RvcmUiICJQcmltYXJ5IGRhdGEgc3RvcmUgZm9yIG1vZGVyYXRpb24gZGVjaXNpb25zLCBibG9ja2xpc3QgZW50cmllcywgYW5kIHJldmlldyBxdWV1ZS4iICJGaXJlYmFzZSBGaXJlc3RvcmUiICJEYXRhYmFzZSIKICAgICAgICAgICAgbW9kZXJhdGlvbl9tb25nb2RiID0gY29udGFpbmVyICJNb25nb0RCIiAiQWx0ZXJuYXRpdmUgZGF0YWJhc2UgYmFja2VuZCBmb3IgdGhlIG1vZGVyYXRpb24gc2VydmljZS4gU2VsZWN0ZWQgdmlhIERBVEFCQVNFX0FEQVBURVIgZW52IHZhci4iICJNb25nb0RCIDciICJEYXRhYmFzZSwgYWx0ZXJuYXRpdmUiCiAgICAgICAgfQoKICAgICAgICAvLyAtLS0gUHVibGlzaGVyIEludGVncmF0aW9uIC0tLQogICAgICAgIHB1Ymxpc2hlcl9pbnRlZ3JhdGlvbiA9IHNvZnR3YXJlU3lzdGVtICJQdWJsaXNoZXIgSW50ZWdyYXRpb24gVG9vbHMiICJUb29scyBmb3IgZGVtb25zdHJhdGluZyBhbmQgaW50ZWdyYXRpbmcgUFNJIGludG8gYnJvYWRjYXN0ZXIgd2Vic2l0ZXMuIEluY2x1ZGVzIGEgY29udGVudCBwcm94eSBhbmQgYSBOZXh0LmpzIGRlbW8gYXBwbGljYXRpb24uIiAib3duZWQiIHsKICAgICAgICAgICAgZGVtb19wcm94eSA9IGNvbnRhaW5lciAiQ29udGVudCBQcm94eSAoRGVtbyBQcm94eSkiICJSZXZlcnNlIHByb3h5IHRoYXQgcmV3cml0ZXMgcHVibGlzaGVyIHdlYiBwYWdlcyB0byBpbmplY3QgdGhlIHBzaS5qcyBzY3JpcHQsIGVuYWJsaW5nIHNpZGViYXIgYW5kIHRlYXNlciBpZnJhbWVzIG9uIGFueSBwdWJsaXNoZXIgc2l0ZS4iICJOb2RlLmpzIiAibXMiCiAgICAgICAgICAgIHB1Ymxpc2hlcl9kZW1vID0gY29udGFpbmVyICJQdWJsaXNoZXIgRGVtbyIgIk5leHQuanMgZXhhbXBsZSBhcHBsaWNhdGlvbiBkZW1vbnN0cmF0aW5nIGhvdyBwYXJ0bmVycyBpbnRlZ3JhdGUgUFNJIHRlYXNlcnMgYW5kIHNpZGViYXIgaW50byB0aGVpciBzaXRlcyB1c2luZyBzZXJ2ZXItc2lkZSBSZWFjdC4iICJOZXh0LmpzIDE0LCBUeXBlU2NyaXB0IiAiV2ViQnJvd3NlciIKICAgICAgICB9CgogICAgICAgIC8vIC0tLSBGaXJlYmFzZSBQbGF0Zm9ybSAtLS0KICAgICAgICBmaXJlYmFzZSA9IHNvZnR3YXJlU3lzdGVtICJGaXJlYmFzZSBQbGF0Zm9ybSIgIkdvb2dsZSBGaXJlYmFzZSBzZXJ2aWNlcyBwcm92aWRpbmcgYXV0aGVudGljYXRpb24sIHJlYWx0aW1lIGRhdGFiYXNlLCBjbG91ZCBmdW5jdGlvbnMgaG9zdGluZywgZmlsZSBzdG9yYWdlLCBGaXJlc3RvcmUsIGFuZCBzdGF0aWMgaG9zdGluZy4iICJHb29nbGUgQ2xvdWQgUGxhdGZvcm0iCgogICAgICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQogICAgICAgIC8vIFJlbGF0aW9uc2hpcHM6IFBlb3BsZSAtPiBTeXN0ZW1zCiAgICAgICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiAgICAgICAgdXNlciAtPiBwc2kgIlBhcnRpY2lwYXRlcyBpbiBjb252ZXJzYXRpb25zLCB3cml0ZXMgY29tbWVudHMsIGFuc3dlcnMgcXVlc3Rpb25zIgogICAgICAgIHVzZXIgLT4gYnJvYWRjYXN0ZXIgIlZpc2l0cyBicm9hZGNhc3RlciB3ZWJzaXRlIgogICAgICAgIG1vZGVyYXRvciAtPiBwc2kgIk1vZGVyYXRlcyBjb250ZW50IHZpYSBtb2RlcmF0aW9uIGRhc2hib2FyZCIKICAgICAgICBlZGl0b3IgLT4gcHNpICJDcmVhdGVzIGFuZCBtYW5hZ2VzIGNvbnZlcnNhdGlvbnMgdmlhIGVkaXRvcmlhbCBkYXNoYm9hcmQiCiAgICAgICAgZWRpdG9yIC0+IGJyb2FkY2FzdGVyLmJyb2FkY2FzdGVyX2NtcyAiUHVibGlzaGVzIGVkaXRvcmlhbCBjb250ZW50IgogICAgICAgIGRldmVsb3BlciAtPiBwc2kgIkRldmVsb3BzIGZlYXR1cmVzIGFuZCBpbnRlZ3JhdGlvbnMiCiAgICAgICAgZGV2ZWxvcGVyIC0+IHB1Ymxpc2hlcl9pbnRlZ3JhdGlvbiAiVGVzdHMgUFNJIGludGVncmF0aW9uIG9uIHB1Ymxpc2hlciBzaXRlcyIKCiAgICAgICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiAgICAgICAgLy8gUmVsYXRpb25zaGlwczogU3lzdGVtcyAtPiBTeXN0ZW1zCiAgICAgICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiAgICAgICAgcHNpIC0+IGZpcmViYXNlICJBdXRoZW50aWNhdGVzIHVzZXJzLCBzdG9yZXMgZGF0YSwgaG9zdHMgYXBwbGljYXRpb24iCiAgICAgICAgcHNpIC0+IGlkZW50aXR5X3Byb3ZpZGVyICJEZWxlZ2F0ZXMgU1NPIGF1dGhlbnRpY2F0aW9uIHZpYSBPSURDIgogICAgICAgIHBzaSAtPiBvcGVuYWkgIlNlbmRzIGNvbW1lbnRzIGZvciBBSSBwcmUtbW9kZXJhdGlvbiwgcmFua2luZywgdHJhbnNsYXRpb24iCiAgICAgICAgcHNpIC0+IHBlcnNwZWN0aXZlX2FwaSAiU2NvcmVzIGNvbnRlbnQgdG94aWNpdHkiCiAgICAgICAgcHNpIC0+IGVtYWlsX3NlcnZpY2UgIlNlbmRzIG5vdGlmaWNhdGlvbiBhbmQgdmVyaWZpY2F0aW9uIGVtYWlscyIKICAgICAgICBwc2kgLT4gc2VudHJ5ICJSZXBvcnRzIGVycm9ycyBhbmQgcGVyZm9ybWFuY2UgZGF0YSIKICAgICAgICBwc2kgLT4gYmlncXVlcnkgIlN0cmVhbXMgZXZlbnQgbG9ncyBmb3IgYW5hbHl0aWNzIgogICAgICAgIHBzaSAtPiB0cmFuc2xhdGlvbl9zZXJ2aWNlICJUcmFuc2xhdGVzIGNvbW1lbnRzIGJldHdlZW4gbGFuZ3VhZ2VzIgogICAgICAgIHBzaSAtPiBnb29nbGVfY2xvdWRfbG9nZ2luZyAiU3RydWN0dXJlZCBldmVudCBsb2dnaW5nIgogICAgICAgIGJyb2FkY2FzdGVyIC0+IHBzaSAiRW1iZWRzIFBTSSBjb252ZXJzYXRpb25zIHZpYSBpZnJhbWVzIGFuZCBzY3JpcHRzIgogICAgICAgIG1vZGVyYXRpb24gLT4gb3BlbmFpICJDYWxscyBMTE0gZm9yIGNvbnRlbnQgbW9kZXJhdGlvbiBkZWNpc2lvbnMiCiAgICAgICAgbW9kZXJhdGlvbiAtPiBwZXJzcGVjdGl2ZV9hcGkgIlNjb3JlcyBjb250ZW50IHRveGljaXR5IgogICAgICAgIG1vZGVyYXRpb24gLT4gc2VudHJ5ICJSZXBvcnRzIGVycm9ycyIKICAgICAgICBwdWJsaXNoZXJfaW50ZWdyYXRpb24gLT4gcHNpICJEZW1vbnN0cmF0ZXMgUFNJIGVtYmVkZGluZyIKICAgICAgICBwdWJsaXNoZXJfaW50ZWdyYXRpb24gLT4gYnJvYWRjYXN0ZXIgIlByb3hpZXMgYW5kIHJld3JpdGVzIGJyb2FkY2FzdGVyIHBhZ2VzIgoKICAgICAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KICAgICAgICAvLyBSZWxhdGlvbnNoaXBzOiBDb250YWluZXJzIChQU0kgaW50ZXJuYWwpCiAgICAgICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgogICAgICAgIC8vIEZyb250ZW5kIC0+IEJhY2tlbmQKICAgICAgICBwc2kuZnJvbnRlbmQgLT4gcHNpLmJhY2tlbmRfZmlyZWJhc2UgIkFQSSBjYWxscyB2aWEgSFRUUFMgKC9hcGkvKikiICJSRVNUL0pTT04iCiAgICAgICAgcHNpLmZyb250ZW5kIC0+IHBzaS5iYWNrZW5kX2V4cHJlc3MgIkFQSSBjYWxscyB2aWEgSFRUUFMgKC9hcGkvKikgW2FsdGVybmF0aXZlIGRlcGxveW1lbnRdIiAiUkVTVC9KU09OIgoKICAgICAgICAvLyBGcm9udGVuZCAtPiBGaXJlYmFzZQogICAgICAgIHBzaS5mcm9udGVuZCAtPiBwc2kuZmlyZWJhc2VfYXV0aCAiU2lnbi1pbiAoR29vZ2xlLCBjdXN0b20gdG9rZW4pIiAiRmlyZWJhc2UgU0RLIgogICAgICAgIHBzaS5mcm9udGVuZCAtPiBwc2kuZmlyZWJhc2VfcnRkYiAiUmVhZHMgcmVhbC10aW1lIGRhdGEgW2RpcmVjdCBtb2RlXSIgIkZpcmViYXNlIFNESyIKICAgICAgICBwc2kuZnJvbnRlbmQgLT4gcHNpLmZpcmViYXNlX3N0b3JhZ2UgIlVwbG9hZHMgdXNlciBmaWxlcyIgIkZpcmViYXNlIFNESyIKCiAgICAgICAgLy8gQmFja2VuZCAtPiBEYXRhIHN0b3JlcwogICAgICAgIHBzaS5iYWNrZW5kX2ZpcmViYXNlIC0+IHBzaS5maXJlYmFzZV9ydGRiICJSZWFkcyBhbmQgd3JpdGVzIHNpbG8vaW5zdGFuY2UgZGF0YSIgIkZpcmViYXNlIEFkbWluIFNESyIKICAgICAgICBwc2kuYmFja2VuZF9maXJlYmFzZSAtPiBwc2kubW9uZ29kYiAiUmVhZHMgYW5kIHdyaXRlcyBkYXRhIFthbHRlcm5hdGl2ZV0iICJNb25nb0RCIGRyaXZlciIKICAgICAgICBwc2kuYmFja2VuZF9maXJlYmFzZSAtPiBwc2kuZmlyZWJhc2VfYXV0aCAiVmVyaWZpZXMgdG9rZW5zLCBjcmVhdGVzIHVzZXJzIiAiRmlyZWJhc2UgQWRtaW4gU0RLIgogICAgICAgIHBzaS5iYWNrZW5kX2ZpcmViYXNlIC0+IHBzaS5maXJlYmFzZV9zdG9yYWdlICJNYW5hZ2VzIHN0b3JlZCBmaWxlcyIgIkZpcmViYXNlIEFkbWluIFNESyIKICAgICAgICBwc2kuYmFja2VuZF9leHByZXNzIC0+IHBzaS5maXJlYmFzZV9ydGRiICJSZWFkcyBhbmQgd3JpdGVzIHNpbG8vaW5zdGFuY2UgZGF0YSIgIkZpcmViYXNlIEFkbWluIFNESyIKICAgICAgICBwc2kuYmFja2VuZF9leHByZXNzIC0+IHBzaS5tb25nb2RiICJSZWFkcyBhbmQgd3JpdGVzIGRhdGEgW2FsdGVybmF0aXZlXSIgIk1vbmdvREIgZHJpdmVyIgogICAgICAgIHBzaS5iYWNrZW5kX2V4cHJlc3MgLT4gcHNpLmZpcmViYXNlX2F1dGggIlZlcmlmaWVzIHRva2VucywgY3JlYXRlcyB1c2VycyIgIkZpcmViYXNlIEFkbWluIFNESyIKCiAgICAgICAgLy8gQmFja2VuZCAtPiBFeHRlcm5hbCBzZXJ2aWNlcwogICAgICAgIHBzaS5iYWNrZW5kX2ZpcmViYXNlIC0+IG9wZW5haSAiUE9TVCAvdjEvY2hhdC9jb21wbGV0aW9ucyIgIkhUVFBTIgogICAgICAgIHBzaS5iYWNrZW5kX2ZpcmViYXNlIC0+IHBlcnNwZWN0aXZlX2FwaSAiUE9TVCAvdjFhbHBoYTEvY29tbWVudHM6YW5hbHl6ZSIgIkhUVFBTIgogICAgICAgIHBzaS5iYWNrZW5kX2ZpcmViYXNlIC0+IGVtYWlsX3NlcnZpY2UgIlNlbmQgdHJhbnNhY3Rpb25hbCBlbWFpbHMiICJIVFRQUyIKICAgICAgICBwc2kuYmFja2VuZF9maXJlYmFzZSAtPiBzZW50cnkgIkVycm9yIHJlcG9ydHMiICJIVFRQUyIKICAgICAgICBwc2kuYmFja2VuZF9maXJlYmFzZSAtPiBiaWdxdWVyeSAiU3RyZWFtIGV2ZW50IGxvZ3MiICJIVFRQUyIKICAgICAgICBwc2kuYmFja2VuZF9maXJlYmFzZSAtPiB0cmFuc2xhdGlvbl9zZXJ2aWNlICJUcmFuc2xhdGUgdGV4dCIgIkhUVFBTIgogICAgICAgIHBzaS5iYWNrZW5kX2ZpcmViYXNlIC0+IGdvb2dsZV9jbG91ZF9sb2dnaW5nICJTdHJ1Y3R1cmVkIGxvZ3MiICJIVFRQUyIKCiAgICAgICAgLy8gRnJvbnRlbmQgLT4gSWRlbnRpdHkgUHJvdmlkZXIKICAgICAgICBwc2kuZnJvbnRlbmQgLT4gaWRlbnRpdHlfcHJvdmlkZXIuaWRwX2FwcCAiUmVkaXJlY3RzIHVzZXIgZm9yIFNTTyBsb2dpbiIgIk9JREMiCiAgICAgICAgaWRlbnRpdHlfcHJvdmlkZXIuaWRwX2FwcCAtPiBwc2kuZnJvbnRlbmQgIlJldHVybnMgSUQgdG9rZW4gYWZ0ZXIgYXV0aGVudGljYXRpb24iICJPSURDIHJlZGlyZWN0IgoKICAgICAgICAvLyBCcm9hZGNhc3RlciBpbnRlcm5hbAogICAgICAgIGJyb2FkY2FzdGVyLmJyb2FkY2FzdGVyX2NtcyAtPiBicm9hZGNhc3Rlci5icm9hZGNhc3Rlcl9mcm9udGVuZCAiUHVibGlzaGVzIGNvbnRlbnQiCgogICAgICAgIC8vIEJyb2FkY2FzdGVyIC0+IFBTSQogICAgICAgIGJyb2FkY2FzdGVyLmJyb2FkY2FzdGVyX2Zyb250ZW5kIC0+IHBzaS5mcm9udGVuZCAiRW1iZWRzIFBTSSBzaWRlYmFyIGFuZCB0ZWFzZXJzIHZpYSBpZnJhbWVzIiAiSFRNTC9KUyIKCiAgICAgICAgLy8gUHVibGlzaGVyIEludGVncmF0aW9uCiAgICAgICAgcHVibGlzaGVyX2ludGVncmF0aW9uLmRlbW9fcHJveHkgLT4gYnJvYWRjYXN0ZXIuYnJvYWRjYXN0ZXJfZnJvbnRlbmQgIlByb3hpZXMgYW5kIGluamVjdHMgcHNpLmpzIHNjcmlwdCIgIkhUVFAgcmV2ZXJzZSBwcm94eSIKICAgICAgICBwdWJsaXNoZXJfaW50ZWdyYXRpb24ucHVibGlzaGVyX2RlbW8gLT4gcHNpLmJhY2tlbmRfZmlyZWJhc2UgIkZldGNoZXMgcXVlc3Rpb24gbWV0YWRhdGEgZm9yIHRlYXNlcnMiICJSRVNUL0pTT04iCgogICAgICAgIC8vIE1vZGVyYXRpb24gU2VydmljZQogICAgICAgIG1vZGVyYXRpb24ubW9kZXJhdGlvbl9hcGkgLT4gb3BlbmFpICJUd28tcGFzcyBtb2RlcmF0aW9uOiBsaWdodCBtb2RlbCB0aGVuIGhlYXZ5IG1vZGVsIiAiSFRUUFMiCiAgICAgICAgbW9kZXJhdGlvbi5tb2RlcmF0aW9uX2FwaSAtPiBwZXJzcGVjdGl2ZV9hcGkgIlRveGljaXR5IHNjb3JpbmciICJIVFRQUyIKICAgICAgICBtb2RlcmF0aW9uLm1vZGVyYXRpb25fYXBpIC0+IG1vZGVyYXRpb24ubW9kZXJhdGlvbl9maXJlc3RvcmUgIlN0b3JlcyBtb2RlcmF0aW9uIGRlY2lzaW9ucyBhbmQgYmxvY2tsaXN0IiAiRmlyZWJhc2UgQWRtaW4gU0RLIgogICAgICAgIG1vZGVyYXRpb24ubW9kZXJhdGlvbl9hcGkgLT4gbW9kZXJhdGlvbi5tb2RlcmF0aW9uX21vbmdvZGIgIlN0b3JlcyBkYXRhIFthbHRlcm5hdGl2ZV0iICJNb25nb0RCIGRyaXZlciIKICAgICAgICBtb2RlcmF0aW9uLm1vZGVyYXRpb25fYXBpIC0+IHNlbnRyeSAiRXJyb3IgcmVwb3J0cyIgIkhUVFBTIgogICAgICAgIG1vZGVyYXRpb24ubW9kZXJhdGlvbl9hcGkgLT4gZW1haWxfc2VydmljZSAiU2VuZHMgbW9kZXJhdGlvbiBub3RpZmljYXRpb24gZW1haWxzIiAiSFRUUFMiCgogICAgICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQogICAgICAgIC8vIFJlbGF0aW9uc2hpcHM6IEJhY2tlbmQgQ29tcG9uZW50cwogICAgICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQogICAgICAgIHBzaS5iYWNrZW5kX2ZpcmViYXNlLmFwaV9yb3V0ZXIgLT4gcHNpLmJhY2tlbmRfZmlyZWJhc2UuYXV0aF9hZGFwdGVyICJBdXRoZW50aWNhdGVzIGluY29taW5nIHJlcXVlc3RzIgogICAgICAgIHBzaS5iYWNrZW5kX2ZpcmViYXNlLmFwaV9yb3V0ZXIgLT4gcHNpLmJhY2tlbmRfZmlyZWJhc2Uuc2VydmVyX3N0b3JlICJDcmVhdGVzIHNjb3BlZCBTZXJ2ZXJTdG9yZSBwZXIgcmVxdWVzdCIKICAgICAgICBwc2kuYmFja2VuZF9maXJlYmFzZS5hcGlfcm91dGVyIC0+IHBzaS5iYWNrZW5kX2ZpcmViYXNlLmNvcmVfbW9kdWxlcyAiRGlzcGF0Y2hlcyB0byBtb2R1bGUgcHVibGljL2FkbWluIGZ1bmN0aW9ucyIKICAgICAgICBwc2kuYmFja2VuZF9maXJlYmFzZS5hcGlfcm91dGVyIC0+IHBzaS5iYWNrZW5kX2ZpcmViYXNlLnBhcnRuZXJfbW9kdWxlcyAiRGlzcGF0Y2hlcyB0byBwYXJ0bmVyIG1vZHVsZSBmdW5jdGlvbnMiCiAgICAgICAgcHNpLmJhY2tlbmRfZmlyZWJhc2Uuc2VydmVyX3N0b3JlIC0+IHBzaS5iYWNrZW5kX2ZpcmViYXNlLmRiX2FkYXB0ZXIgIlJlYWRzIGFuZCB3cml0ZXMgZGF0YSB0aHJvdWdoIGFkYXB0ZXIiCiAgICAgICAgcHNpLmJhY2tlbmRfZmlyZWJhc2UuYXV0aF9hZGFwdGVyIC0+IHBzaS5maXJlYmFzZV9hdXRoICJWZXJpZmllcyBGaXJlYmFzZSBJRCB0b2tlbnMiCiAgICAgICAgcHNpLmJhY2tlbmRfZmlyZWJhc2UuYXV0aF9hZGFwdGVyIC0+IGlkZW50aXR5X3Byb3ZpZGVyLmlkcF9hcHAgIkZldGNoZXMgSldLUyBmb3IgSldUIHZlcmlmaWNhdGlvbiIKICAgICAgICBwc2kuYmFja2VuZF9maXJlYmFzZS5kYl9hZGFwdGVyIC0+IHBzaS5maXJlYmFzZV9ydGRiICJGaXJlYmFzZSBSVERCIGltcGxlbWVudGF0aW9uIgogICAgICAgIHBzaS5iYWNrZW5kX2ZpcmViYXNlLmRiX2FkYXB0ZXIgLT4gcHNpLm1vbmdvZGIgIk1vbmdvREIgaW1wbGVtZW50YXRpb24iCiAgICAgICAgcHNpLmJhY2tlbmRfZmlyZWJhc2UuZW1haWxfYWRhcHRlciAtPiBlbWFpbF9zZXJ2aWNlICJTZW5kcyBlbWFpbHMgdmlhIGNvbmZpZ3VyZWQgcHJvdmlkZXIiCiAgICAgICAgcHNpLmJhY2tlbmRfZmlyZWJhc2UubGxtX2FkYXB0ZXIgLT4gb3BlbmFpICJDYWxscyBPcGVuQUkvQXp1cmUgT3BlbkFJIgogICAgICAgIHBzaS5iYWNrZW5kX2ZpcmViYXNlLmxsbV9hZGFwdGVyIC0+IHBlcnNwZWN0aXZlX2FwaSAiQ2FsbHMgUGVyc3BlY3RpdmUgQVBJIgogICAgICAgIHBzaS5iYWNrZW5kX2ZpcmViYXNlLnRyYW5zbGF0aW9uX2FkYXB0ZXIgLT4gdHJhbnNsYXRpb25fc2VydmljZSAiVHJhbnNsYXRlcyB2aWEgRGVlcEwvVGV4dFNodXR0bGUvU1JHIFNTUiIKICAgICAgICBwc2kuYmFja2VuZF9maXJlYmFzZS50cmFuc2xhdGlvbl9hZGFwdGVyIC0+IG9wZW5haSAiVHJhbnNsYXRlcyB2aWEgR1BUIChMTE0gYWRhcHRlciBtb2RlKSIKICAgICAgICBwc2kuYmFja2VuZF9maXJlYmFzZS5jb3JlX21vZHVsZXMgLT4gcHNpLmJhY2tlbmRfZmlyZWJhc2Uuc2VydmVyX3N0b3JlICJEYXRhIGFjY2VzcyB2aWEgc2NvcGVkIHN0b3JlIgogICAgICAgIHBzaS5iYWNrZW5kX2ZpcmViYXNlLmNvcmVfbW9kdWxlcyAtPiBwc2kuYmFja2VuZF9maXJlYmFzZS5sbG1fYWRhcHRlciAiQUkgbW9kZXJhdGlvbiBhbmQgcmFua2luZyBjYWxscyIKICAgICAgICBwc2kuYmFja2VuZF9maXJlYmFzZS5jb3JlX21vZHVsZXMgLT4gcHNpLmJhY2tlbmRfZmlyZWJhc2UuZW1haWxfYWRhcHRlciAiU2VuZHMgbm90aWZpY2F0aW9uIGVtYWlscyIKICAgICAgICBwc2kuYmFja2VuZF9maXJlYmFzZS5jb3JlX21vZHVsZXMgLT4gcHNpLmJhY2tlbmRfZmlyZWJhc2UudHJhbnNsYXRpb25fYWRhcHRlciAiQ29udGVudCB0cmFuc2xhdGlvbiBjYWxscyIKICAgICAgICBwc2kuYmFja2VuZF9maXJlYmFzZS5wYXJ0bmVyX21vZHVsZXMgLT4gcHNpLmJhY2tlbmRfZmlyZWJhc2Uuc2VydmVyX3N0b3JlICJEYXRhIGFjY2VzcyB2aWEgc2NvcGVkIHN0b3JlIgogICAgICAgIHBzaS5iYWNrZW5kX2ZpcmViYXNlLnBhcnRuZXJfbW9kdWxlcyAtPiBwc2kuYmFja2VuZF9maXJlYmFzZS5sbG1fYWRhcHRlciAiQUkgY2FsbHMgKGNvbnZlcnNhdGlvbiBoZWxwZXIsIGV0Yy4pIgoKICAgICAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KICAgICAgICAvLyBSZWxhdGlvbnNoaXBzOiBGcm9udGVuZCBDb21wb25lbnRzCiAgICAgICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiAgICAgICAgcHNpLmZyb250ZW5kLnN0cnVjdHVyZXMgLT4gcHNpLmZyb250ZW5kLmNsaWVudF9kYXRhc3RvcmUgIlJlYWRzIGluc3RhbmNlIGRhdGEgdmlhIGhvb2tzIgogICAgICAgIHBzaS5mcm9udGVuZC5mZWF0dXJlcyAtPiBwc2kuZnJvbnRlbmQuY2xpZW50X2RhdGFzdG9yZSAiUmVhZHMgYW5kIHdyaXRlcyBkYXRhIHZpYSBob29rcyBhbmQgY2FsbGJhY2tzIgogICAgICAgIHBzaS5mcm9udGVuZC5mZWF0dXJlcyAtPiBwc2kuZnJvbnRlbmQuc3RydWN0dXJlcyAiRXh0ZW5kcyB2aWEgY29uZmlnIHNsb3RzICh3aWRnZXRzLCBjYWxsYmFja3MsIGRhdGEpIgogICAgICAgIHBzaS5mcm9udGVuZC5zdHJ1Y3R1cmVzIC0+IHBzaS5mcm9udGVuZC5kZXNpZ25fc3lzdGVtICJVc2VzIHNoYXJlZCBVSSBjb21wb25lbnRzIgogICAgICAgIHBzaS5mcm9udGVuZC5mZWF0dXJlcyAtPiBwc2kuZnJvbnRlbmQuZGVzaWduX3N5c3RlbSAiVXNlcyBzaGFyZWQgVUkgY29tcG9uZW50cyIKICAgICAgICBwc2kuZnJvbnRlbmQuc3RydWN0dXJlcyAtPiBwc2kuZnJvbnRlbmQudHJhbnNsYXRpb25zICJEaXNwbGF5cyB0cmFuc2xhdGVkIHN0cmluZ3MgdmlhIHQoKSBmdW5jdGlvbiIKICAgICAgICBwc2kuZnJvbnRlbmQuZmVhdHVyZXMgLT4gcHNpLmZyb250ZW5kLnRyYW5zbGF0aW9ucyAiRGlzcGxheXMgdHJhbnNsYXRlZCBzdHJpbmdzIHZpYSB0KCkgZnVuY3Rpb24iCiAgICAgICAgcHNpLmZyb250ZW5kLmNsaWVudF9kYXRhc3RvcmUgLT4gcHNpLmZyb250ZW5kLmNsaWVudF9kYl9hZGFwdGVyICJEZWxlZ2F0ZXMgZGF0YSBvcGVyYXRpb25zIgogICAgICAgIHBzaS5mcm9udGVuZC5jbGllbnRfZGJfYWRhcHRlciAtPiBwc2kuZmlyZWJhc2VfcnRkYiAiRmlyZWJhc2UgZGlyZWN0IGNvbm5lY3Rpb24iCiAgICAgICAgcHNpLmZyb250ZW5kLmNsaWVudF9kYl9hZGFwdGVyIC0+IHBzaS5iYWNrZW5kX2ZpcmViYXNlICJTZXJ2ZXItcHJveGllZCBkYXRhIGFjY2VzcyAoU2VydmVyRGF0YWJhc2VBZGFwdGVyKSIKICAgICAgICBwc2kuZnJvbnRlbmQuY2xpZW50X2F1dGhfYWRhcHRlciAtPiBwc2kuZmlyZWJhc2VfYXV0aCAiRmlyZWJhc2UgQXV0aCBTREsiCiAgICAgICAgcHNpLmZyb250ZW5kLmNsaWVudF9vcGVuX21vZHVsZXMgLT4gcHNpLmZyb250ZW5kLnN0cnVjdHVyZXMgIkV4dGVuZHMgY29yZSBzdHJ1Y3R1cmVzIgogICAgICAgIHBzaS5mcm9udGVuZC5jbGllbnRfb3Blbl9tb2R1bGVzIC0+IHBzaS5mcm9udGVuZC5mZWF0dXJlcyAiQWRkcyBwYXJ0bmVyLXNwZWNpZmljIGZlYXR1cmVzIgogICAgICAgIHBzaS5mcm9udGVuZC5jbGllbnRfb3Blbl9tb2R1bGVzIC0+IHBzaS5mcm9udGVuZC5jbGllbnRfZGF0YXN0b3JlICJVc2VzIGRhdGEgYWNjZXNzIEFQSXMiCiAgICB9CgogICAgdmlld3MgewoKICAgICAgICBwcm9wZXJ0aWVzIHsKICAgICAgICAgICAgIm1lcm1haWQudXJsIiAiaHR0cHM6Ly9tZXJtYWlkLmluayIKICAgICAgICAgICAgIm1lcm1haWQuZm9ybWF0IiAicG5nIgogICAgICAgIH0KCiAgICAgICAgLy8gTGV2ZWwgMDogU3lzdGVtIExhbmRzY2FwZQogICAgICAgIHN5c3RlbUxhbmRzY2FwZSAic3lzdGVtTGFuZHNjYXBlX3BzaSIgIk92ZXJ2aWV3IG9mIGFsbCBzeXN0ZW1zIGFuZCBwZW9wbGUgaW52b2x2ZWQgaW4gdGhlIFBTSSBlY29zeXN0ZW0iIHsKICAgICAgICAgICAgaW5jbHVkZSAqCiAgICAgICAgfQoKICAgICAgICAvLyBMZXZlbCAxOiBTeXN0ZW0gQ29udGV4dCAtIFBTSQogICAgICAgIHN5c3RlbUNvbnRleHQgcHNpICJzeXN0ZW1Db250ZXh0X3BzaSIgIlRoZSBQU0kgc3lzdGVtIGluIGNvbnRleHQgd2l0aCBpdHMgZXh0ZXJuYWwgZGVwZW5kZW5jaWVzIiB7CiAgICAgICAgICAgIGluY2x1ZGUgKgogICAgICAgICAgICBhdXRvTGF5b3V0IHRiIDQwMCAyMDAKICAgICAgICB9CgogICAgICAgIC8vIExldmVsIDI6IENvbnRhaW5lcnMgLSBQU0kgU3lzdGVtCiAgICAgICAgY29udGFpbmVyIHBzaSAiY29udGFpbmVyc19wc2kiICJJbnRlcm5hbCBjb250YWluZXJzIG9mIHRoZSBQU0kgc3lzdGVtIiB7CiAgICAgICAgICAgIGluY2x1ZGUgKgogICAgICAgICAgICBhdXRvTGF5b3V0IHRiIDQwMCAyMDAKICAgICAgICB9CgogICAgICAgIC8vIExldmVsIDI6IENvbnRhaW5lcnMgLSBCcm9hZGNhc3RlciBTeXN0ZW0KICAgICAgICBjb250YWluZXIgYnJvYWRjYXN0ZXIgImNvbnRhaW5lcnNfYnJvYWRjYXN0ZXIiICJCcm9hZGNhc3RlciBzeXN0ZW0gY29udGFpbmVycyIgewogICAgICAgICAgICBpbmNsdWRlICoKICAgICAgICAgICAgYXV0b0xheW91dCB0YiAzMDAgMjAwCiAgICAgICAgfQoKICAgICAgICAvLyBMZXZlbCAyOiBDb250YWluZXJzIC0gSWRlbnRpdHkgUHJvdmlkZXIKICAgICAgICBjb250YWluZXIgaWRlbnRpdHlfcHJvdmlkZXIgImNvbnRhaW5lcnNfaWRlbnRpdHlfcHJvdmlkZXIiICJJZGVudGl0eSBwcm92aWRlciBjb250YWluZXJzIiB7CiAgICAgICAgICAgIGluY2x1ZGUgKgogICAgICAgICAgICBhdXRvTGF5b3V0IHRiIDMwMCAyMDAKICAgICAgICB9CgogICAgICAgIC8vIExldmVsIDI6IENvbnRhaW5lcnMgLSBNb2RlcmF0aW9uIFNlcnZpY2UKICAgICAgICBjb250YWluZXIgbW9kZXJhdGlvbiAiY29udGFpbmVyc19tb2RlcmF0aW9uIiAiTW9kZXJhdGlvbiBzZXJ2aWNlIGNvbnRhaW5lcnMiIHsKICAgICAgICAgICAgaW5jbHVkZSAqCiAgICAgICAgICAgIGF1dG9MYXlvdXQgdGIgMzAwIDIwMAogICAgICAgIH0KCiAgICAgICAgLy8gTGV2ZWwgMjogQ29udGFpbmVycyAtIFB1Ymxpc2hlciBJbnRlZ3JhdGlvbgogICAgICAgIGNvbnRhaW5lciBwdWJsaXNoZXJfaW50ZWdyYXRpb24gImNvbnRhaW5lcnNfcHVibGlzaGVyIiAiUHVibGlzaGVyIGludGVncmF0aW9uIHRvb2wgY29udGFpbmVycyIgewogICAgICAgICAgICBpbmNsdWRlICoKICAgICAgICAgICAgYXV0b0xheW91dCB0YiAzMDAgMjAwCiAgICAgICAgfQoKICAgICAgICAvLyBMZXZlbCAzOiBDb21wb25lbnRzIC0gUFNJIEJhY2tlbmQKICAgICAgICBjb21wb25lbnQgcHNpLmJhY2tlbmRfZmlyZWJhc2UgImNvbXBvbmVudHNfcHNpX2JhY2tlbmQiICJJbnRlcm5hbCBjb21wb25lbnRzIG9mIHRoZSBQU0kgYmFja2VuZCIgewogICAgICAgICAgICBpbmNsdWRlICoKICAgICAgICAgICAgYXV0b0xheW91dCB0YiA0MDAgMjAwCiAgICAgICAgfQoKICAgICAgICAvLyBMZXZlbCAzOiBDb21wb25lbnRzIC0gUFNJIEZyb250ZW5kCiAgICAgICAgY29tcG9uZW50IHBzaS5mcm9udGVuZCAiY29tcG9uZW50c19wc2lfZnJvbnRlbmQiICJJbnRlcm5hbCBjb21wb25lbnRzIG9mIHRoZSBQU0kgZnJvbnRlbmQiIHsKICAgICAgICAgICAgaW5jbHVkZSAqCiAgICAgICAgICAgIGF1dG9MYXlvdXQgdGIgMzAwIDIwMAogICAgICAgIH0KCiAgICAgICAgLy8gU3R5bGVzCiAgICAgICAgc3R5bGVzIHsKICAgICAgICAgICAgZWxlbWVudCAiUGVyc29uIiB7CiAgICAgICAgICAgICAgICBzaGFwZSBQZXJzb24KICAgICAgICAgICAgfQogICAgICAgICAgICBlbGVtZW50ICJvd25lZCIgewogICAgICAgICAgICAgICAgYmFja2dyb3VuZCAjMTE2OEJECiAgICAgICAgICAgICAgICBjb2xvciAjZmZmZmZmCiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxlbWVudCAiZm9yZWlnbiIgewogICAgICAgICAgICAgICAgYmFja2dyb3VuZCAjOTk5OTk5CiAgICAgICAgICAgICAgICBjb2xvciAjZmZmZmZmCiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxlbWVudCAiZXh0ZXJuYWwiIHsKICAgICAgICAgICAgICAgIGJhY2tncm91bmQgIzk5OTk5OQogICAgICAgICAgICAgICAgY29sb3IgI2ZmZmZmZgogICAgICAgICAgICB9CiAgICAgICAgICAgIGVsZW1lbnQgInVzZXIiIHsKICAgICAgICAgICAgICAgIGJhY2tncm91bmQgIzA4NDI3QgogICAgICAgICAgICAgICAgY29sb3IgI2ZmZmZmZgogICAgICAgICAgICB9CiAgICAgICAgICAgIGVsZW1lbnQgImRldmVsb3BlciIgewogICAgICAgICAgICAgICAgYmFja2dyb3VuZCAjMkQ4ODJECiAgICAgICAgICAgICAgICBjb2xvciAjZmZmZmZmCiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxlbWVudCAibXMiIHsKICAgICAgICAgICAgICAgIHNoYXBlIGhleGFnb24KICAgICAgICAgICAgfQogICAgICAgICAgICBlbGVtZW50ICJEYXRhYmFzZSIgewogICAgICAgICAgICAgICAgc2hhcGUgY3lsaW5kZXIKICAgICAgICAgICAgfQogICAgICAgICAgICBlbGVtZW50ICJXZWJCcm93c2VyIiB7CiAgICAgICAgICAgICAgICBzaGFwZSBXZWJCcm93c2VyCiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxlbWVudCAiYWx0ZXJuYXRpdmUiIHsKICAgICAgICAgICAgICAgIGJhY2tncm91bmQgIzZCOEU5QgogICAgICAgICAgICAgICAgY29sb3IgI2ZmZmZmZgogICAgICAgICAgICAgICAgYm9yZGVyIGRhc2hlZAogICAgICAgICAgICB9CiAgICAgICAgICAgIGVsZW1lbnQgIkdvb2dsZSBDbG91ZCBQbGF0Zm9ybSIgewogICAgICAgICAgICAgICAgYmFja2dyb3VuZCAjNDI4NUY0CiAgICAgICAgICAgICAgICBjb2xvciAjZmZmZmZmCiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9Cgp9"},"views":{"componentViews":[{"automaticLayout":{"applied":true,"edgeSeparation":0,"implementation":"Graphviz","nodeSeparation":200,"rankDirection":"TopBottom","rankSeparation":400,"vertices":false},"containerId":"22","description":"Internal components of the PSI backend","dimensions":{"height":3639,"width":6141},"elements":[{"id":"5","x":4191,"y":2283},{"id":"6","x":3541,"y":2283},{"id":"7","x":5491,"y":2283},{"id":"10","x":4841,"y":2283},{"id":"23","x":1141,"y":183},{"id":"24","x":2224,"y":883},{"id":"25","x":274,"y":2283},{"id":"26","x":2224,"y":1583},{"id":"27","x":924,"y":1583},{"id":"28","x":1574,"y":1583},{"id":"29","x":274,"y":1583},{"id":"30","x":1466,"y":883},{"id":"31","x":816,"y":883},{"id":"33","x":220,"y":2983},{"id":"34","x":870,"y":2983},{"id":"36","x":2882,"y":1583},{"id":"40","x":3541,"y":1583}],"externalContainerBoundariesVisible":false,"key":"components_psi_backend","name":"Component View: PSI System - PSI Backend (Cloud Functions)","order":8,"relationships":[{"id":"116"},{"id":"117","vertices":[{"x":716,"y":883}]},{"id":"118"},{"id":"119"},{"id":"120"},{"id":"121"},{"id":"123"},{"id":"126"},{"id":"127"},{"id":"128","vertices":[{"x":2691,"y":1883},{"x":5391,"y":2283}]},{"id":"129","vertices":[{"x":1474,"y":1883},{"x":4091,"y":2283}]},{"id":"130","vertices":[{"x":1474,"y":1883}]},{"id":"131","vertices":[{"x":2124,"y":1883},{"x":4741,"y":2283}]},{"id":"132","vertices":[{"x":2124,"y":1883},{"x":4091,"y":2283}]},{"id":"133"},{"id":"134"},{"id":"135"},{"id":"136"},{"id":"137"},{"id":"138"}]},{"automaticLayout":{"applied":false,"edgeSeparation":0,"implementation":"Graphviz","nodeSeparation":200,"rankDirection":"TopBottom","rankSeparation":300,"vertices":false},"containerId":"13","description":"Internal components of the PSI frontend","elements":[{"id":"14","x":0,"y":0},{"id":"15","x":0,"y":0},{"id":"16","x":0,"y":0},{"id":"17","x":0,"y":0},{"id":"18","x":0,"y":0},{"id":"19","x":0,"y":0},{"id":"20","x":0,"y":0},{"id":"21","x":0,"y":0},{"id":"22","x":0,"y":0},{"id":"33","x":0,"y":0},{"id":"36","x":0,"y":0}],"externalContainerBoundariesVisible":false,"key":"components_psi_frontend","name":"Component View: PSI System - PSI Frontend","order":9,"relationships":[{"id":"139"},{"id":"140"},{"id":"141"},{"id":"142"},{"id":"143"},{"id":"144"},{"id":"145"},{"id":"146"},{"id":"147"},{"id":"148"},{"id":"149"},{"id":"150"},{"id":"151"},{"id":"152"},{"id":"78"},{"id":"80"}]}],"configuration":{"branding":{},"lastSavedView":"components_psi_backend","metadataSymbols":"SquareBrackets","properties":{"mermaid.format":"png","mermaid.url":"https://mermaid.ink"},"styles":{"elements":[{"background":"#6b8e9b","border":"Dashed","color":"#ffffff","tag":"alternative"},{"shape":"Cylinder","tag":"Database"},{"background":"#2d882d","color":"#ffffff","tag":"developer"},{"background":"#999999","color":"#ffffff","tag":"external"},{"background":"#999999","color":"#ffffff","tag":"foreign"},{"background":"#4285f4","color":"#ffffff","tag":"Google Cloud Platform"},{"shape":"Hexagon","tag":"ms"},{"background":"#1168bd","color":"#ffffff","tag":"owned"},{"shape":"Person","tag":"Person"},{"background":"#08427b","color":"#ffffff","tag":"user"},{"shape":"WebBrowser","tag":"WebBrowser"}]},"terminology":{}},"containerViews":[{"automaticLayout":{"applied":true,"edgeSeparation":0,"implementation":"Graphviz","nodeSeparation":200,"rankDirection":"TopBottom","rankSeparation":400,"vertices":false},"description":"Internal containers of the PSI system","dimensions":{"height":3688,"width":7378},"elements":[{"id":"5","x":6728,"y":2943},{"id":"6","x":2828,"y":2943},{"id":"7","x":3478,"y":2943},{"id":"8","x":4128,"y":2943},{"id":"9","x":4778,"y":2943},{"id":"10","x":5428,"y":2943},{"id":"11","x":6078,"y":2943},{"id":"13","x":1741,"y":1543},{"id":"22","x":2170,"y":2243},{"id":"32","x":928,"y":2243},{"id":"33","x":220,"y":2943},{"id":"34","x":1520,"y":2943},{"id":"35","x":2170,"y":2943},{"id":"36","x":870,"y":2943},{"id":"37","x":1741,"y":843},{"id":"40","x":2828,"y":2243},{"id":"46","x":1474,"y":143}],"externalSoftwareSystemBoundariesVisible":false,"key":"containers_psi","name":"Container View: PSI System","order":3,"relationships":[{"id":"102"},{"id":"108","vertices":[{"x":1641,"y":843},{"x":1641,"y":1843}]},{"id":"125"},{"id":"72"},{"id":"73"},{"id":"74"},{"id":"75","vertices":[{"x":1478,"y":2543}]},{"id":"76","vertices":[{"x":828,"y":2243}]},{"id":"77","vertices":[{"x":2070,"y":2543}]},{"id":"78","vertices":[{"x":770,"y":2943}]},{"id":"79"},{"id":"80"},{"id":"81"},{"id":"82"},{"id":"83"},{"id":"84"},{"id":"85","vertices":[{"x":2728,"y":2543},{"x":6628,"y":2943}]},{"id":"86"},{"id":"87"},{"id":"88","vertices":[{"x":2728,"y":2543},{"x":4028,"y":2943}]},{"id":"89","vertices":[{"x":2728,"y":2543},{"x":4678,"y":2943}]},{"id":"90","vertices":[{"x":2728,"y":2543},{"x":5328,"y":2943}]},{"id":"91","vertices":[{"x":2728,"y":2543},{"x":5978,"y":2943}]},{"id":"93","vertices":[{"x":2428,"y":2169}]},{"id":"97","vertices":[{"x":2590,"y":1916}]}],"softwareSystemId":"12"},{"automaticLayout":{"applied":true,"edgeSeparation":0,"implementation":"Graphviz","nodeSeparation":200,"rankDirection":"TopBottom","rankSeparation":300,"vertices":false},"description":"Broadcaster system containers","dimensions":{"height":2600,"width":1765},"elements":[{"id":"3","x":210,"y":142},{"id":"12","x":456,"y":2042},{"id":"38","x":456,"y":1442},{"id":"39","x":456,"y":842},{"id":"46","x":1114,"y":842}],"externalSoftwareSystemBoundariesVisible":false,"key":"containers_broadcaster","name":"Container View: Broadcaster System","order":4,"relationships":[{"id":"101"},{"id":"105"},{"id":"53","vertices":[{"x":302,"y":738},{"x":302,"y":1846}]},{"id":"54"},{"id":"71","vertices":[{"x":1060,"y":1846}]},{"id":"99"}],"softwareSystemId":"37"},{"automaticLayout":{"applied":true,"edgeSeparation":0,"implementation":"Graphviz","nodeSeparation":200,"rankDirection":"TopBottom","rankSeparation":300,"vertices":false},"description":"Identity provider containers","dimensions":{"height":1488,"width":907},"elements":[{"id":"12","x":228,"y":142},{"id":"41","x":228,"y":742}],"externalSoftwareSystemBoundariesVisible":false,"key":"containers_identity_provider","name":"Container View: Identity Provider","order":5,"relationships":[{"id":"94","vertices":[{"x":303,"y":614}]},{"id":"96","vertices":[{"x":603,"y":614}]}],"softwareSystemId":"40"},{"automaticLayout":{"applied":false,"edgeSeparation":0,"implementation":"Graphviz","nodeSeparation":200,"rankDirection":"TopBottom","rankSeparation":300,"vertices":false},"description":"Moderation service containers","elements":[{"id":"5","x":0,"y":0},{"id":"6","x":0,"y":0},{"id":"7","x":0,"y":0},{"id":"8","x":0,"y":0},{"id":"43","x":0,"y":0},{"id":"44","x":0,"y":0},{"id":"45","x":0,"y":0}],"externalSoftwareSystemBoundariesVisible":false,"key":"containers_moderation","name":"Container View: Moderation Service","order":6,"relationships":[{"id":"109"},{"id":"110"},{"id":"111"},{"id":"112"},{"id":"113"},{"id":"114"}],"softwareSystemId":"42"},{"automaticLayout":{"applied":true,"edgeSeparation":0,"implementation":"Graphviz","nodeSeparation":200,"rankDirection":"TopBottom","rankSeparation":300,"vertices":false},"description":"Publisher integration tool containers","dimensions":{"height":1920,"width":1540},"elements":[{"id":"12","x":540,"y":1362},{"id":"37","x":277,"y":762},{"id":"47","x":219,"y":162},{"id":"48","x":869,"y":162}],"externalSoftwareSystemBoundariesVisible":false,"key":"containers_publisher","name":"Container View: Publisher Integration Tools","order":7,"relationships":[{"id":"104"},{"id":"107"},{"id":"67"}],"softwareSystemId":"46"}],"systemContextViews":[{"automaticLayout":{"applied":true,"edgeSeparation":0,"implementation":"Graphviz","nodeSeparation":200,"rankDirection":"TopBottom","rankSeparation":400,"vertices":false},"description":"The PSI system in context with its external dependencies","dimensions":{"height":3800,"width":6050},"elements":[{"id":"1","x":1438,"y":942},{"id":"2","x":1734,"y":1742},{"id":"3","x":2396,"y":942},{"id":"4","x":3438,"y":142},{"id":"5","x":2800,"y":3242},{"id":"6","x":3450,"y":3242},{"id":"7","x":4100,"y":3242},{"id":"8","x":4750,"y":3242},{"id":"9","x":5400,"y":3242},{"id":"10","x":200,"y":3242},{"id":"11","x":850,"y":3242},{"id":"12","x":2475,"y":2542},{"id":"37","x":2742,"y":1792},{"id":"40","x":1500,"y":3242},{"id":"46","x":3150,"y":992},{"id":"49","x":2150,"y":3242}],"enterpriseBoundaryVisible":true,"key":"systemContext_psi","name":"System Context View: PSI System","order":2,"relationships":[{"id":"50","vertices":[{"x":1634,"y":1742},{"x":1634,"y":2142}]},{"id":"51"},{"id":"52"},{"id":"53","vertices":[{"x":2642,"y":2142}]},{"id":"55"},{"id":"56","vertices":[{"x":3700,"y":942},{"x":3700,"y":1342},{"x":3463,"y":2142}]},{"id":"57"},{"id":"58"},{"id":"59","vertices":[{"x":2125,"y":2920}]},{"id":"60"},{"id":"61"},{"id":"62","vertices":[{"x":4000,"y":3242}]},{"id":"63","vertices":[{"x":4650,"y":3242}]},{"id":"64","vertices":[{"x":5300,"y":3242}]},{"id":"65","vertices":[{"x":750,"y":3242}]},{"id":"66","vertices":[{"x":1400,"y":3242}]},{"id":"67"},{"id":"71","vertices":[{"x":3292,"y":2142}]},{"id":"72"},{"id":"98","vertices":[{"x":2299,"y":3163}]}],"softwareSystemId":"12"}],"systemLandscapeViews":[{"description":"Overview of all systems and people involved in the PSI ecosystem","dimensions":{"height":4100,"width":5950},"elements":[{"id":"1","x":549,"y":143},{"id":"2","x":1549,"y":143},{"id":"3","x":2549,"y":143},{"id":"4","x":4349,"y":143},{"id":"5","x":1899,"y":3543},{"id":"6","x":2749,"y":3543},{"id":"7","x":3599,"y":3543},{"id":"8","x":4389,"y":3538},{"id":"9","x":5299,"y":3543},{"id":"10","x":199,"y":3543},{"id":"11","x":1049,"y":3543},{"id":"12","x":2209,"y":1718},{"id":"37","x":800,"y":930},{"id":"40","x":1489,"y":2463},{"id":"42","x":4369,"y":2038},{"id":"46","x":4344,"y":953},{"id":"49","x":549,"y":2643}],"enterpriseBoundaryVisible":true,"key":"systemLandscape_psi","name":"System Landscape View","order":1,"relationships":[{"id":"115","vertices":[{"x":4199,"y":2193},{"x":3824,"y":2193}]},{"id":"50","vertices":[{"x":699,"y":1893}]},{"id":"51","vertices":[{"x":714,"y":1078}]},{"id":"52","vertices":[{"x":1699,"y":1893}]},{"id":"53","vertices":[{"x":2740,"y":1155}]},{"id":"55","vertices":[{"x":2724,"y":948}]},{"id":"56","vertices":[{"x":4549,"y":1443},{"x":2424,"y":1443}]},{"id":"57"},{"id":"58","vertices":[{"x":774,"y":2193}]},{"id":"59","vertices":[{"x":2274,"y":2343}]},{"id":"60","vertices":[{"x":2124,"y":3193}]},{"id":"61","vertices":[{"x":2989,"y":2463}]},{"id":"62","vertices":[{"x":2424,"y":3093},{"x":3824,"y":3093}]},{"id":"63","vertices":[{"x":2424,"y":3193},{"x":4624,"y":3223}]},{"id":"64","vertices":[{"x":2424,"y":3293},{"x":5524,"y":3293}]},{"id":"65","vertices":[{"x":424,"y":2193}]},{"id":"66","vertices":[{"x":1274,"y":2193}]},{"id":"67","vertices":[{"x":1024,"y":1543}]},{"id":"68","vertices":[{"x":4574,"y":3693}]},{"id":"69","vertices":[{"x":4574,"y":3293},{"x":2974,"y":3293}]},{"id":"70"},{"id":"71","vertices":[{"x":4554,"y":1543}]},{"id":"72","vertices":[{"x":4574,"y":743},{"x":1024,"y":743}]},{"id":"98","vertices":[{"x":2379,"y":2458}]}]}]}}