Repository: inket/stts Branch: master Commit: 2bd78c67e090 Files: 167 Total size: 17.1 MB Directory structure: gitextract_a2ozbqvp/ ├── .bundle/ │ └── config ├── .gitattributes ├── .gitignore ├── .swiftlint.yml ├── Cartfile ├── Cartfile.resolved ├── Gemfile ├── LICENSE ├── README.md ├── Resources/ │ ├── AppIcon.icon/ │ │ └── icon.json │ ├── Assets.xcassets/ │ │ └── Contents.json │ ├── Base.lproj/ │ │ └── MainMenu.xib │ ├── Info.plist │ └── services.json ├── Scripts/ │ ├── generate_adobe_services.swift │ ├── generate_apple_services.swift │ ├── generate_aws_services.swift │ ├── generate_azure_devops_services.swift │ ├── generate_azure_services.swift │ ├── generate_google_services.swift │ ├── generate_salesforce_services.swift │ └── generate_services_plist.sh ├── extract.rb ├── openai.html ├── sort.rb ├── stts/ │ ├── AppDelegate.swift │ ├── AppearanceObserver.swift │ ├── BottomBar.swift │ ├── CustomScrollView.swift │ ├── DataLoader.swift │ ├── EditorTableView/ │ │ └── EditorTableCell.swift │ ├── Extensions/ │ │ ├── Atomic.swift │ │ ├── NSScreenExtensions.swift │ │ ├── StringExtensions.swift │ │ └── TaskExtensions.swift │ ├── HeadlessHTMLRenderer.swift │ ├── Icons.swift │ ├── Preferences/ │ │ ├── PreferencesGeneralView.swift │ │ ├── PreferencesServicesView.swift │ │ └── PreferencesWindow.swift │ ├── Preferences.swift │ ├── PreferencesWindow/ │ │ ├── NSAppearance+Extensions.swift │ │ ├── PreferencesAboutView.swift │ │ ├── PreferencesSidebarMenu.swift │ │ └── PreferencesWindowController.swift │ ├── ServiceLoader/ │ │ ├── AppDefinedServiceDefinitionProvider.swift │ │ ├── BundleServiceDefinitionProvider.swift │ │ ├── ServiceDefinition.swift │ │ ├── ServiceDefinitionProvider.swift │ │ ├── ServiceLoader.swift │ │ ├── ServicesStructure.swift │ │ └── UserDefinedServiceDefinitionProvider.swift │ ├── ServiceTableView/ │ │ ├── ServiceTableRowView.swift │ │ ├── ServiceTableViewController.swift │ │ ├── StatusIndicator.swift │ │ └── StatusTableCell.swift │ ├── Services/ │ │ ├── Algolia.swift │ │ ├── AzureAll.swift │ │ ├── AzureDevOpsAll.swift │ │ ├── Beanstalk.swift │ │ ├── Broadcom.swift │ │ ├── Evernote.swift │ │ ├── Fastly.swift │ │ ├── Firebase.swift │ │ ├── Generated/ │ │ │ ├── AWSServices.swift │ │ │ ├── AdobeServices.swift │ │ │ ├── AppleServices.swift │ │ │ ├── AzureDevOpsServices.swift │ │ │ ├── AzureServices.swift │ │ │ ├── FirebaseServices.swift │ │ │ ├── GoogleCloudPlatformServices.swift │ │ │ └── SalesforceProducts.swift │ │ ├── GoogleCloudPlatformAll.swift │ │ ├── MiroAll.swift │ │ ├── Okta.swift │ │ ├── OracleNetSuite.swift │ │ ├── PagerDuty/ │ │ │ └── PagerDuty.swift │ │ ├── PayPal/ │ │ │ ├── PayPalAPIProduction.swift │ │ │ ├── PayPalAPISandbox.swift │ │ │ ├── PayPalProductProduction.swift │ │ │ └── PayPalProductSandbox.swift │ │ ├── PlayStation Network/ │ │ │ ├── PSNAmerica.swift │ │ │ ├── PSNAsia.swift │ │ │ └── PSNEurope.swift │ │ ├── SendbirdAll.swift │ │ ├── SignalWire.swift │ │ ├── Slack.swift │ │ ├── Stripe.swift │ │ ├── Super/ │ │ │ ├── AWSService.swift │ │ │ ├── AWSStore.swift │ │ │ ├── Adobe.swift │ │ │ ├── AdobeStore.swift │ │ │ ├── Apple.swift │ │ │ ├── AppleDeveloper.swift │ │ │ ├── AppleStore.swift │ │ │ ├── Azure.swift │ │ │ ├── AzureDevOps.swift │ │ │ ├── AzureDevOpsStore.swift │ │ │ ├── AzureStore.swift │ │ │ ├── BetterStackService.swift │ │ │ ├── BetterUptimeService.swift │ │ │ ├── CStateService.swift │ │ │ ├── CachetService.swift │ │ │ ├── ExanaService.swift │ │ │ ├── FirebaseService.swift │ │ │ ├── FirebaseStatusDashboardStore.swift │ │ │ ├── GoogleCloudPlatform.swift │ │ │ ├── GoogleStatusDashboardStore.swift │ │ │ ├── IncidentIOService.swift │ │ │ ├── IndependentService.swift │ │ │ ├── InstatusService.swift │ │ │ ├── LambStatusService.swift │ │ │ ├── MiroService.swift │ │ │ ├── PagerDutyService.swift │ │ │ ├── PayPal.swift │ │ │ ├── PlayStationNetwork.swift │ │ │ ├── Salesforce.swift │ │ │ ├── SalesforceCategories.swift │ │ │ ├── SalesforceStore.swift │ │ │ ├── SendbirdService.swift │ │ │ ├── Service.swift │ │ │ ├── ServiceStore.swift │ │ │ ├── Site24x7Service.swift │ │ │ ├── SorryService.swift │ │ │ ├── StatusCakeService.swift │ │ │ ├── StatusCastService.swift │ │ │ ├── StatusHubService.swift │ │ │ ├── StatusPageService.swift │ │ │ ├── StatusioV1Service.swift │ │ │ ├── StatuspalService.swift │ │ │ └── UptimeDotComService.swift │ │ ├── UptimeDotCom/ │ │ │ ├── JSDelivr.swift │ │ │ ├── Recurly.swift │ │ │ └── UptimeDotCom.swift │ │ └── Zendesk.swift │ ├── SwitchableTableViewController.swift │ └── stts.entitlements ├── stts.xcodeproj/ │ ├── project.pbxproj │ ├── project.xcworkspace/ │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata/ │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm/ │ │ └── Package.resolved │ └── xcshareddata/ │ └── xcschemes/ │ └── stts.xcscheme └── sttsTests/ ├── AdobeTests.swift ├── BetterStackTests.swift ├── Helpers/ │ └── TestBundle.swift ├── IncidentIOTests.swift ├── Info.plist ├── InstatusTests.swift ├── MiroTests.swift ├── Mocks/ │ ├── ResponseOverridingURLSession.swift │ └── ResponseSizeTrackingURLSession.swift ├── PagerDutyTests.swift ├── Resources/ │ ├── adobe-analytics-minor.json │ ├── aiven-minor.html │ ├── buildjet-good.html │ ├── eyloo-major.html │ ├── linear-good.html │ ├── mastodonsocial-major.html │ ├── miro-good.html │ ├── miro-issue.html │ ├── openai-major.html │ ├── pagerduty-good.html │ ├── pagerduty-minor.html │ ├── rollbar-good.html │ └── whereby-good.html ├── StringExtensionsTests.swift └── sttsTests.swift ================================================ FILE CONTENTS ================================================ ================================================ FILE: .bundle/config ================================================ --- BUNDLE_PATH: "vendor/bundle" BUNDLE_FORCE_RUBY_PLATFORM: "true" ================================================ FILE: .gitattributes ================================================ sttsTests/Resources/** linguist-vendored ================================================ FILE: .gitignore ================================================ # Created by https://www.gitignore.io/api/swift ### Swift ### # Xcode # # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore ## Build generated build/ DerivedData/ ## Various settings *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata/ ## Other *.moved-aside *.xcuserstate ## Obj-C/Swift specific *.hmap *.ipa *.dSYM.zip *.dSYM ## Playgrounds timeline.xctimeline playground.xcworkspace # Swift Package Manager # # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. # Packages/ .build/ # CocoaPods # # We recommend against adding the Pods directory to your .gitignore. However # you should judge for yourself, the pros and cons are mentioned at: # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control # # Pods/ # Carthage # # Add this line if you want to avoid checking in source code from Carthage dependencies. Carthage/Checkouts Carthage/Build # fastlane # # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the # screenshots whenever they are needed. # For more information about the recommended setup visit: # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md fastlane/report.xml fastlane/Preview.html fastlane/screenshots fastlane/test_output # Ignore App Store assets (screenshots) App Store # Ruby vendor vendor # Claude CLAUDE.md .claude/ ================================================ FILE: .swiftlint.yml ================================================ excluded: - Pods - Carthage line_length: warning: 120 ignores_comments: true ignores_interpolated_strings: true disabled_rules: - type_body_length - function_body_length - nesting - identifier_name - file_length - for_where - blanket_disable_command ================================================ FILE: Cartfile ================================================ github "inket/StartAtLogin" ================================================ FILE: Cartfile.resolved ================================================ github "inket/StartAtLogin" "v6.0.0" ================================================ FILE: Gemfile ================================================ source 'https://rubygems.org' gem 'xcodeproj' gem 'synx' ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2016 Mahdi Bchetnia Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ ## stts ![](https://img.shields.io/badge/Swift-5-orange.svg) stts is a macOS app for monitoring the status of cloud services. With a click of the menubar icon, you can see the status of your favorite services. You can also be notified when a service goes down or gets restored. stts is designed to be unobtrusive, only giving you the information you need and allowing you to access the status page with a single click. stts can be downloaded from the Mac App Store [here](https://itunes.apple.com/app/stts/id1187772509?l=en&mt=12). ### Support the project Buy Me A Coffee ### Contribute Most services can be added automatically with the included extract script: ```sh # If you haven't already, clone the repo git clone https://github.com/inket/stts.git cd stts # Install dependencies and run the extract script bundle install bundle exec ruby extract.rb # Example: bundle exec ruby extract.rb https://status.notion.so/ ``` For services that cannot be added with the script, feel free to create an issue. #### Contact [@inket](https://github.com/inket) / [@inket](https://twitter.com/inket) on Twitter / [mahdi.jp](https://mahdi.jp) ================================================ FILE: Resources/AppIcon.icon/icon.json ================================================ { "fill" : { "linear-gradient" : [ "display-p3:0.27726,0.27726,0.27726,1.00000", "display-p3:0.18033,0.18033,0.18033,1.00000" ] }, "groups" : [ { "blend-mode" : "normal", "blur-material" : null, "hidden" : false, "layers" : [ { "blend-mode" : "normal", "fill-specializations" : [ { "value" : { "linear-gradient" : [ "display-p3:0.99663,0.99663,0.99663,1.00000", "display-p3:0.89697,0.89697,0.89697,1.00000" ] } }, { "appearance" : "dark", "value" : { "linear-gradient" : [ "display-p3:0.99663,0.99663,0.99663,1.00000", "display-p3:0.89697,0.89697,0.89697,1.00000" ] } } ], "glass" : true, "hidden" : false, "image-name" : "noun-activity-680031.svg", "name" : "noun-activity-680031", "opacity" : 0.9, "position" : { "scale" : 6, "translation-in-points" : [ 30, 90 ] } } ], "lighting" : "individual", "shadow" : { "kind" : "neutral", "opacity" : 0.5 }, "specular" : false, "translucency" : { "enabled" : false, "value" : 0.5 } } ], "supported-platforms" : { "circles" : [ "watchOS" ], "squares" : "shared" } } ================================================ FILE: Resources/Assets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Resources/Base.lproj/MainMenu.xib ================================================ Default Left to Right Right to Left Default Left to Right Right to Left ================================================ FILE: Resources/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIconFile AppIcon.icon CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString $(MARKETING_VERSION) CFBundleSignature ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) ITSAppUsesNonExemptEncryption LSApplicationCategoryType public.app-category.utilities LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) LSUIElement NSAppTransportSecurity NSExceptionDomains status.aws.amazon.com NSExceptionMinimumTLSVersion TLSv1.0 NSExceptionRequiresForwardSecrecy status.beanstalkapp.com NSExceptionAllowsInsecureHTTPLoads status.evernote.com NSExceptionAllowsInsecureHTTPLoads NSHumanReadableCopyright Copyright © 2016 Mahdi Bchetnia. All rights reserved. NSMainNibFile MainMenu NSPrincipalClass NSApplication ================================================ FILE: Resources/services.json ================================================ { "betterstack": [ { "name": "Better Stack", "url": "https://status.betterstack.com", "old_names": [ "BetterStack" ] }, { "name": "BuildJet", "url": "https://status.buildjet.com" }, { "name": "Keygen", "url": "https://status.keygen.sh" }, { "name": "Runway: App Store Connect", "url": "https://runway-asc.betteruptime.com", "old_names": [ "RunwayASC" ] }, { "name": "Unraid", "url": "https://status.unraid.net" } ], "betteruptime": [ { "name": "Plausible Analytics", "url": "https://status.plausible.io", "old_names": [ "PlausibleAnalytics" ] }, { "name": "Runway", "url": "https://status.runway.team" }, ], "cstate": [ { "name": "Civo", "url": "https://status.civo.com/" } ], "incidentio": [ { "name": "Aiven", "url": "https://status.aiven.io" }, { "name": "Brevo", "url": "https://status.brevo.com", "old_names": [ "Sendinblue" ] }, { "name": "Code Climate", "url": "https://status.codeclimate.com", "old_names": [ "CodeClimate" ] }, { "name": "HashiCorp", "url": "https://status.hashicorp.com" }, { "name": "Intercom - AU Hosting", "url": "https://www.intercomstatus.com/au-hosting", "old_names": [ "IntercomAU" ] }, { "name": "Intercom - EU Hosting", "url": "https://www.intercomstatus.com/eu-hosting", "old_names": [ "IntercomEU" ] }, { "name": "Intercom - US Hosting", "url": "https://www.intercomstatus.com/us-hosting", "old_names": [ "IntercomUS", "Intercom" ] }, { "name": "Linear", "url": "https://linearstatus.com" }, { "name": "OneSignal", "url": "https://status.onesignal.com" }, { "name": "OpenAI", "url": "https://status.openai.com" }, { "name": "Rollbar", "url": "https://status.rollbar.com" }, { "name": "Strategic Roadmaps", "url": "https://status.roadmunk.com", "old_names": [ "Roadmunk" ] }, { "name": "Tempo", "url": "https://status.tempo.io" }, { "name": "Zapier", "url": "https://status.zapier.com" } ], "instatus": [ { "name": "Bitmovin", "url": "https://status.bitmovin.com" }, { "name": "Instatus", "url": "https://instat.us" }, { "name": "Primcloud", "url": "https://primcloud.instatus.com" }, { "name": "Railway", "url": "https://status.railway.app" }, { "name": "Sketch", "url": "https://status.sketch.com" }, { "name": "Threader", "url": "https://threader.instatus.com" }, { "name": "Whereby", "url": "https://wherebystatus.com" }, { "name": "mastodon.social", "url": "https://status.mastodon.social", "old_names": [ "MastodonSocial" ] } ], "lamb": [ { "name": "Codacy", "url": "https://status.codacy.com" } ], "miro": [ { "name": "Miro (AU)", "url": "https://status.miro.com/au", "subservice": true }, { "name": "Miro (EU)", "url": "https://status.miro.com/eu", "subservice": true }, { "name": "Miro (US)", "url": "https://status.miro.com/us", "subservice": true } ], "site24x7": [ { "name": "Canonical", "url": "https://status.canonical.com", "id": "KNms6QK9ewuzz-7xUsPsN927u5djVcb3oZX1-zOu_go=" }, { "name": "Site24x7", "url": "https://status.site24x7.com", "id": "7Ca9wFlVF-AlbjpE2tzER6FUegHamCQNyZF5CbAffCs=" } ], "sorry": [ { "name": "Pingdom", "url": "https://status.pingdom.com", "id": "2273" }, { "name": "Pipedrive", "url": "https://status.pipedrive.com", "id": "2754" }, { "name": "Postmark", "url": "https://status.postmarkapp.com", "id": "12903" } ], "statusiov1": [ { "name": "ClickUp", "url": "https://status.clickup.com", "id": "5b6e0963c662144d00913a09" }, { "name": "CoreWeave", "url": "https://status.coreweave.com", "id": "5e126e998f2f032e1f8f0f4b" }, { "name": "Dashlane", "url": "https://status.dashlane.com", "id": "5aabcb89fccc4b04d3774443" }, { "name": "Docker", "url": "https://status.docker.com", "id": "533c6539221ae15e3f000031" }, { "name": "GitLab", "url": "https://status.gitlab.com", "id": "5b36dc6502d06804c08349f7" }, { "name": "Let's Encrypt", "url": "https://letsencrypt.status.io", "id": "55957a99e800baa4470002da", "old_names": [ "LetsEncrypt" ] }, { "name": "OneLogin (EU)", "url": "https://status.eu.onelogin.com", "id": "54da2ea0e6bd61bf0d00002b", "old_names": [ "OneLoginEU" ] }, { "name": "OneLogin (US)", "url": "https://status.us.onelogin.com", "id": "538511e2ce5cb97537000144", "old_names": [ "OneLoginUS" ] }, { "name": "Roblox", "url": "https://status.roblox.com", "id": "59db90dbcdeb2f04dadcf16d" }, { "name": "SumoLogic", "url": "https://status.sumologic.com", "id": "5ea1c7ba3f2f1604b93ca38e" } ], "statuscake": [ { "name": "MailChimp", "url": "https://status.mailchimp.com", "id": "58JncZazfp" } ], "statuscast": [ { "name": "8x8", "url": "https://status.8x8.com", "hasCurrentStatus": false, "old_names": [ "EightXEight" ] }, { "name": "Airship (EU)", "url": "https://status.airship.eu", "hasCurrentStatus": true, "old_names": [ "AirshipEU" ] }, { "name": "Airship (US)", "url": "https://status.airship.com", "hasCurrentStatus": true, "old_names": [ "AirshipUS", "UrbanAirship" ] }, { "name": "Campaign Monitor", "url": "https://status.campaignmonitor.com", "hasCurrentStatus": true, "old_names": [ "CampaignMonitor" ] }, { "name": "StatusCast", "url": "https://status.statuscast.com", "hasCurrentStatus": false } ], "statushub": [ { "name": "WP Engine", "url": "https://wpenginestatus.com", "old_names": [ "WPEngine" ] } ], "statuspage": [ { "name": "1Password", "url": "https://1password.statuspage.io", "id": "z5s8xghvb0vf", "old_names": [ "OnePassword" ] }, { "name": "Acoustic", "url": "https://status.goacoustic.com", "id": "rx9084q34820" }, { "name": "Acquia", "url": "https://status.acquia.com", "id": "c3bdbqpxhzcc" }, { "name": "Airbase", "url": "https://status.airbase.com", "id": "pc6tsj7kht1c" }, { "name": "Alert Logic", "url": "https://status.alertlogic.com", "id": "bkbjcmdhhfbp", "old_names": [ "AlertLogic" ] }, { "name": "Anthropic", "url": "https://status.anthropic.com", "id": "tymt9n04zgry" }, { "name": "Aptible", "url": "https://status.aptible.com", "id": "fmwgqnbnbc4r" }, { "name": "Asana", "url": "https://trust.asana.com", "id": "w58858w0sjxx" }, { "name": "Atlassian Access", "url": "https://access.status.atlassian.com", "id": "5qmgwsxwsz78", "old_names": [ "AtlassianAccess" ] }, { "name": "Atlassian Developer", "url": "https://developer.status.atlassian.com", "id": "n8766lc3ybbs", "old_names": [ "AtlassianDeveloper" ] }, { "name": "Atlassian Partners", "url": "https://partners.status.atlassian.com", "id": "tfc0vzc0cq1n", "old_names": [ "AtlassianPartners" ] }, { "name": "Atlassian Statuspage", "url": "https://metastatuspage.com", "id": "y2j98763l56x", "host": "metastatuspage.com", "old_names": [ "StatusPage", "Statuspage" ] }, { "name": "Atlassian Support", "url": "https://support.status.atlassian.com", "id": "3tbw4lb9t3qp", "old_names": [ "AtlassianSupport" ] }, { "name": "AuroraSolar", "url": "https://status.aurorasolar.com", "id": "vbgjcnqcyyw7" }, { "name": "Auth0", "url": "https://status.auth0.com", "id": "8q60stg1rk7l" }, { "name": "Authorize.Net", "url": "https://status.authorize.net", "id": "06v575cbzlpr", "old_names": [ "AuthorizeNet" ] }, { "name": "Avalara", "url": "https://status.avalara.com", "id": "m10fpsk86bhy" }, { "name": "Basecamp", "url": "https://www.basecampstatus.com", "id": "thc30769z1m9" }, { "name": "BigCommerce", "url": "https://status.bigcommerce.com", "id": "qbn4dyd29jby" }, { "name": "Bitbucket", "url": "https://bitbucket.status.atlassian.com", "id": "bqlf8qjztdtr", "old_names": [ "BitBucket" ] }, { "name": "Bitrise", "url": "https://status.bitrise.io", "id": "1q8r4n02vb2k" }, { "name": "Blend", "url": "https://status.blend.com", "id": "wp6n3nr9gm7w" }, { "name": "Bolt", "url": "https://status.bolt.com", "id": "hgyc600tg2jq" }, { "name": "Box", "url": "https://status.box.com", "id": "208q92hckwws" }, { "name": "Branch", "url": "https://status.branch.io", "id": "74brn6fz1jt2" }, { "name": "Bugsnag", "url": "https://status.bugsnag.com", "id": "6xl1gdp6yn0x" }, { "name": "Buildkite", "url": "https://www.buildkitestatus.com", "id": "ltljpr68dygn" }, { "name": "Bullhorn", "url": "https://status.bullhorn.com", "id": "cdxw86qkmw3x" }, { "name": "Chargebee", "url": "https://status.chargebee.com", "id": "7h56br5y94wh" }, { "name": "Checkly", "url": "https://is.checkly.online", "id": "nq8lf8mrmvw6" }, { "name": "CircleCI", "url": "https://status.circleci.com", "id": "6w4r0ttlx5ft" }, { "name": "Click", "url": "https://status.clicksoftware.com", "id": "57wtfpyjb9p3" }, { "name": "Cloud66", "url": "https://status.cloud66.com", "id": "mpfrt81d47gt" }, { "name": "CloudAMQP", "url": "https://status.cloudamqp.com", "id": "2126xm8ctzlk" }, { "name": "CloudApp", "url": "https://status.getcloudapp.com", "id": "jv7lgzmdfxr1" }, { "name": "Cloudflare", "url": "https://www.cloudflarestatus.com", "id": "yh6f0r4529hb" }, { "name": "Cloudinary", "url": "https://status.cloudinary.com", "id": "d8rszhl2bj7r" }, { "name": "Clubhouse", "url": "https://status.clubhouse.io", "id": "27fcn0qntr9w" }, { "name": "CocoaPods", "url": "https://status.cocoapods.org", "id": "7k11xygtyyyg" }, { "name": "Codecov", "url": "https://status.codecov.io", "id": "wdzsn5dlywj9" }, { "name": "CoderPad", "url": "https://status.coderpad.io", "id": "29rb067ttd9j" }, { "name": "Coinbase", "url": "https://status.coinbase.com", "id": "kr0djjh0jyy9" }, { "name": "Compass", "url": "https://compass.status.atlassian.com", "id": "6b7xgjptl20c" }, { "name": "Confluence", "url": "https://confluence.status.atlassian.com", "id": "4g2my7tbhjsq" }, { "name": "Confluent Cloud", "url": "https://status.confluent.cloud", "id": "3yz1tdpdnjl3", "old_names": [ "ConfluentCloud" ] }, { "name": "Contentful", "url": "https://www.contentfulstatus.com", "id": "4bv17htq00cz" }, { "name": "Coveralls", "url": "https://status.coveralls.io", "id": "3h72wtpg5fqs" }, { "name": "Cursor", "url": "https://status.cursor.com/", "id": "0tp9ssgtptvs" }, { "name": "Customer.io", "url": "https://status.customerio.com", "id": "w4qr97njbszt", "old_names": [ "Customerio" ] }, { "name": "Cybersource", "url": "https://status.cybersource.com", "id": "ttbtd8wrjg1b" }, { "name": "Cypress", "url": "https://www.cypressstatus.com/", "id": "prr339fdc8ry" }, { "name": "DNSimple", "url": "https://dnsimple.statuspage.io", "id": "tjym90yyv2zt" }, { "name": "Datadog", "url": "https://status.datadoghq.com", "id": "1k6wzpspjf99" }, { "name": "Datadog (EU)", "url": "https://status.datadoghq.eu", "id": "5by3sysm209d", "old_names": [ "DatadogEU" ] }, { "name": "DeepSeek", "url": "https://status.deepseek.com", "id": "0db0rq26tg1l" }, { "name": "Dialpad", "url": "https://status.dialpad.com", "id": "80trk830s0hg" }, { "name": "DigitalOcean", "url": "https://status.digitalocean.com", "id": "w4cz49tckxhp" }, { "name": "Discord", "url": "https://status.discordapp.com", "id": "srhpyqt94yxb" }, { "name": "Doppler", "url": "https://www.dopplerstatus.com", "id": "05hwsyqkr9z7" }, { "name": "Dropbox", "url": "https://status.dropbox.com", "id": "t34htyd6jblf" }, { "name": "Duo", "url": "https://status.duo.com", "id": "qrxf5mzbrsxw" }, { "name": "Dwolla", "url": "https://status.dwolla.com", "id": "tnynfs0nwlgr" }, { "name": "EasyPost", "url": "https://www.easypoststatus.com", "id": "n1jtz5983249" }, { "name": "Egnyte", "url": "https://status.egnyte.com", "id": "jr196z1ns266" }, { "name": "Elastic Cloud", "url": "https://cloud-status.elastic.co", "id": "8wpbdv4sl8gv", "old_names": [ "ElasticCloud" ] }, { "name": "Emailable", "url": "https://status.emailable.com", "id": "ntzxwsjy15bq" }, { "name": "Engine Yard", "url": "https://status.engineyard.com", "id": "76sphw1bc50q", "old_names": [ "EngineYard" ] }, { "name": "Equinix Metal", "url": "https://status.equinixmetal.com", "id": "39f8vhy6rw5d", "old_names": [ "EquinixMetal", "Packet" ] }, { "name": "Figma", "url": "https://status.figma.com", "id": "rxpksf93ynw6" }, { "name": "Files.com", "url": "https://status.files.com", "id": "qcl58pn3j90b", "old_names": [ "FilesCom", "Lumanox" ] }, { "name": "Filestack", "url": "https://status.filestack.com", "id": "z8cjgbr8sqmh" }, { "name": "Fivetran", "url": "https://status.fivetran.com", "id": "2lfd8mfks09w" }, { "name": "Fleek", "url": "https://status.fleek.xyz", "id": "0flwwyd0s5n2" }, { "name": "Fly.io", "url": "https://status.flyio.net", "id": "65rccr4mbblw", "old_names": [ "Flyio" ] }, { "name": "FreeAgent", "url": "https://status.freeagent.com", "id": "tn2dcgpy021r" }, { "name": "Gandi.net", "url": "https://status.gandi.net", "id": "xnm08yh10bv5", "old_names": [ "Gandi" ] }, { "name": "GitHub", "url": "https://www.githubstatus.com", "id": "kctbh9vrtdwd" }, { "name": "HelloSign / HelloFax", "url": "https://status.hellosign.com", "id": "djw9397fmqd1", "old_names": [ "HelloSignHelloFax" ] }, { "name": "HouseCanary", "url": "https://status.housecanary.com/", "id": "pkkpjjckfnnb" }, { "name": "HubSpot", "url": "https://status.hubspot.com", "id": "8b9w1wwq3g7d" }, { "name": "Internet Computer", "url": "https://status.internetcomputer.org", "id": "kc2llmsd16bk", "old_names": [ "InternetComputer" ] }, { "name": "JAMF", "url": "https://status.jamf.com", "id": "5z7bmx2nb2yj" }, { "name": "Jira Align", "url": "https://jira-align.status.atlassian.com", "id": "jrg4crndtsgz", "old_names": [ "JiraAlign" ] }, { "name": "Jira Product Discovery", "url": "https://jira-product-discovery.status.atlassian.com", "id": "qmzzdxyvmbmk", "old_names": [ "JiraProductDiscovery" ] }, { "name": "Jira Service Management", "url": "https://jira-service-management.status.atlassian.com", "id": "pv54g7ltsc24", "old_names": [ "JiraServiceManagement" ] }, { "name": "Jira Software", "url": "https://jira-software.status.atlassian.com", "id": "7yh3h3y0c0x1", "old_names": [ "JiraSoftware" ] }, { "name": "Jira Work Management", "url": "https://jira-work-management.status.atlassian.com", "id": "s6f0gm5gcpmy", "old_names": [ "JiraWorkManagement" ] }, { "name": "JumpCloud", "url": "https://status.jumpcloud.com", "id": "nflr6k3n1c0h" }, { "name": "KeenIO", "url": "https://status.keen.io", "id": "z3mvdbpvy7yh" }, { "name": "Keeper Security", "url": "https://statuspage.keeper.io", "id": "wg5bvczw1rtf", "old_names": [ "KeeperSecurity" ] }, { "name": "Kentik", "url": "https://status.kentik.com", "id": "25fy3sprxcv3" }, { "name": "Kustomer", "url": "https://status.kustomer.com", "id": "lhn2sb4njk08" }, { "name": "LastPass", "url": "https://status.lastpass.com", "id": "ytnz8gj3wjpg" }, { "name": "Lattice", "url": "https://status.lattice.com", "id": "gj13f8gmt9b6" }, { "name": "LaunchDarkly", "url": "https://status.launchdarkly.com", "id": "9404kdk7lkn7" }, { "name": "Lever", "url": "https://status.lever.co", "id": "34ygfdwr11jd" }, { "name": "LinkedIn API", "url": "https://linkedin.statuspage.io", "id": "mxfydrt8b8xw", "old_names": [ "LinkedInAPI" ] }, { "name": "Linode", "url": "https://status.linode.com", "id": "8dn0wstr1chc" }, { "name": "Lob", "url": "https://lob.statuspage.io", "id": "2xkb3rfdd3lg" }, { "name": "Loggly", "url": "https://status.loggly.com", "id": "701xnxqmhdh3" }, { "name": "Loom", "url": "https://loom.status.atlassian.com", "id": "j9r9w5bcs26w" }, { "name": "Mailgun", "url": "https://status.mailgun.com", "id": "6jp439mdyy0k" }, { "name": "Mapbox", "url": "https://status.mapbox.com", "id": "l363gv8nm9gc" }, { "name": "Medium", "url": "https://medium.statuspage.io", "id": "q9n7m9kv0533" }, { "name": "MeridianLink", "url": "https://status.meridianlink.com", "id": "n1pskh7dw1c1" }, { "name": "MessageBird", "url": "https://status.messagebird.com", "id": "xf8120tyqx8n" }, { "name": "Mixpanel", "url": "https://status.mixpanel.com", "id": "x4m91ldrf511" }, { "name": "Mode Analytics", "url": "https://status.modeanalytics.com", "id": "th35d4vb90h8", "old_names": [ "ModeAnalytics" ] }, { "name": "MongoDB Cloud", "url": "https://status.cloud.mongodb.com", "id": "smhnl3lt74kc", "old_names": [ "MongoDBCloud" ] }, { "name": "Mozilla", "url": "https://status.services.mozilla.com", "id": "29l4z1kld06b", "old_names": [ "FirefoxRelay" ] }, { "name": "Mural", "url": "https://status.mural.co", "id": "dbk70dpy3n7h" }, { "name": "Nasdaq Data Link", "url": "https://status.data.nasdaq.com", "id": "dyfxchz1hcb1", "old_names": [ "NasdaqDataLink", "Quandl" ] }, { "name": "Netlify", "url": "https://www.netlifystatus.com", "id": "83dz7syz0j3x" }, { "name": "New Relic", "url": "https://status.newrelic.com", "id": "nwg5xmnm9d17", "old_names": [ "NewRelic" ] }, { "name": "Notion", "url": "https://status.notion.so", "id": "kgl53swp0yg1" }, { "name": "Opsgenie", "url": "https://opsgenie.status.atlassian.com", "id": "t05vdsszxwtq" }, { "name": "Pantheon", "url": "https://status.pantheon.io", "id": "80f0zgsx80zh" }, { "name": "Papertrail", "url": "https://www.papertrailstatus.com", "id": "0n5jhb30j32t" }, { "name": "Pardot", "url": "https://trust.pardot.com", "id": "j0hnsfnqtllz" }, { "name": "Pendo", "url": "https://status.pendo.io", "id": "qxvy69hcwh22" }, { "name": "Planning Center", "url": "https://status.planningcenter.com", "id": "mj14zc034yxl", "old_names": [ "PlanningCenter" ] }, { "name": "Platform.sh", "url": "https://status.platform.sh", "id": "l2x5n4czt1ph", "old_names": [ "PlatformSH" ] }, { "name": "PlayFab", "url": "https://status.playfab.com", "id": "hndmlgmdcpdk" }, { "name": "Poka", "url": "https://www.pokastatus.io", "id": "6gqznhly63gc" }, { "name": "Productboard", "url": "https://status.productboard.com", "id": "wwwnvh1nlpt1" }, { "name": "Proton", "url": "https://status.proton.me", "id": "wy8ls9q1ttmm", "old_names": [ "ProtonMail" ] }, { "name": "PubNub", "url": "https://status.pubnub.com", "id": "j2pr9thwz01t" }, { "name": "Pusher", "url": "https://status.pusher.com", "id": "p6t5x7tdq8yq" }, { "name": "Python", "url": "https://status.python.org", "id": "2p66nmmycsj3" }, { "name": "QuickBooks", "url": "https://status.quickbooks.intuit.com", "id": "2dv2gqw9hrgc" }, { "name": "ReadMe", "url": "https://www.readmestatus.com", "id": "nz3r09cr7dk1" }, { "name": "Recruiterbox", "url": "https://status.recruiterbox.com", "id": "mnlrk0049tgf" }, { "name": "Red Hat", "url": "https://status.redhat.com", "id": "dn6mqn7xvzz3", "old_names": [ "RedHat" ] }, { "name": "Reddit", "url": "https://www.redditstatus.com", "id": "2kbc0d48tv3j" }, { "name": "RevenueCat", "url": "https://status.revenuecat.com", "id": "d7wjfp7kgjkd" }, { "name": "Robin", "url": "https://status.robinpowered.com", "id": "4hy25vm4h6fc" }, { "name": "Robinhood", "url": "https://status.robinhood.com", "id": "49plxygx5s1k" }, { "name": "RubyGems", "url": "https://status.rubygems.org", "id": "pclby00q90vc" }, { "name": "Sauce Labs", "url": "https://status.saucelabs.com", "id": "kd2w7ghdk56w", "old_names": [ "SauceLabs" ] }, { "name": "Scaleway", "url": "https://status.scaleway.com", "id": "s2kbtscly3pj" }, { "name": "SecurID", "url": "https://status.securid.com", "id": "1xw7gmwkm0bg" }, { "name": "Segment", "url": "https://status.segment.com", "id": "yzw83vcxbysq" }, { "name": "Semaphore", "url": "https://status.semaphoreci.com", "id": "zq6qk8cct5d8" }, { "name": "SendGrid", "url": "https://status.sendgrid.com", "id": "3tgl2vf85cht" }, { "name": "Sentry", "url": "https://status.sentry.io", "id": "t687h3m0nh65" }, { "name": "Shopify", "url": "https://www.shopifystatus.com", "id": "d33g96wd23dd" }, { "name": "Smarty", "url": "https://status.smarty.com", "id": "q1z5r94tnt56", "old_names": [ "SmartyStreets" ] }, { "name": "Snowflake", "url": "https://status.snowflake.com", "id": "94s7z8vpy1n8" }, { "name": "Snyk", "url": "https://snyk.statuspage.io", "id": "myj6w6kw42c6" }, { "name": "Squarespace", "url": "https://status.squarespace.com", "id": "1jkhm1drpysj" }, { "name": "Stream", "url": "https://status.getstream.io", "id": "gsms7w17y9wc" }, { "name": "Teleport Cloud", "url": "https://status.teleport.sh", "id": "j16wc0h3wc86", "old_names": [ "TeleportCloud" ] }, { "name": "Temporal", "url": "https://status.temporal.io", "id": "dnmfkqzkp304" }, { "name": "TravisCI", "url": "https://www.traviscistatus.com", "id": "pnpcptp8xh9k" }, { "name": "Trello", "url": "https://trello.status.atlassian.com", "id": "h5frqhb041yq" }, { "name": "Twilio", "url": "https://status.twilio.com", "id": "gpkpyklzq55q" }, { "name": "Twitch", "url": "https://status.twitch.tv", "id": "yfj40zdsk34s" }, { "name": "Tyk", "url": "https://status.tyk.io/", "id": "wygv0lcrzvq7" }, { "name": "Typeform", "url": "https://status.typeform.com", "id": "fv5fyw3p7k8n" }, { "name": "Unsplash", "url": "https://status.unsplash.com", "id": "gcw6g25tpdkv" }, { "name": "VMware Workspace ONE", "url": "https://status.workspaceone.com", "id": "3l65ysrm5cly", "old_names": [ "VMwareWorkspaceONE" ] }, { "name": "Vercel", "url": "https://www.vercel-status.com", "id": "lvglq8h0mdyh" }, { "name": "VictorOps", "url": "https://status.victorops.com", "id": "tj7j024mr40d" }, { "name": "Vimeo", "url": "https://www.vimeostatus.com", "id": "sccqh0pnqrh8" }, { "name": "Visual Studio App Center", "url": "https://status.appcenter.ms", "id": "kkc10kz2t8yc", "old_names": [ "VisualStudioAppCenter" ] }, { "name": "Wasabi", "url": "https://status.wasabi.com", "id": "2r1tdgqr8ld5" }, { "name": "WeTransfer", "url": "https://wetransfer.statuspage.io", "id": "sc26zwwp3c0r" }, { "name": "Wiz", "url": "https://status.wiz.io/", "id": "bgx79l11xfsj" }, { "name": "Wodby", "url": "https://status.wodby.com", "id": "hmm9v8wzw86x" }, { "name": "Workflowy", "url": "https://status.workflowy.com", "id": "m8f43n57h83g" }, { "name": "Xandr", "url": "https://status.xandr.com", "id": "z7jb4dcjs0nl" }, { "name": "Zoom", "url": "https://status.zoom.us", "id": "14qjgk812kgk" }, { "name": "Zwift", "url": "https://status.zwift.com", "id": "sj50pfj5p1yv" }, { "name": "bunny.net", "url": "https://status.bunny.net", "id": "jggkjgplmcdc", "old_names": [ "Bunnynet" ] }, { "name": "imgix", "url": "https://status.imgix.com", "id": "032k0f0j3bsz", "old_names": [ "Imgix" ] }, { "name": "logz.io", "url": "https://status.logz.io", "id": "flbqdmg201t4", "old_names": [ "LogzIO" ] }, { "name": "npm", "url": "https://status.npmjs.org", "id": "wyvgptkd90hm", "old_names": [ "NPM" ] } ], "statuspal": [ { "name": "Booxi", "url": "https://status.booxi.com" }, { "name": "Exoscale", "url": "https://exoscalestatus.com" }, { "name": "Unity", "url": "https://status.unity.com" } ], "sendbird": [ { "name": "Sendbird (Canada)", "url": "https://status-canada.sendbird.com", "id": "xnlfmklffhwg", "subservice": true, "old_names": [ "SendbirdCanada" ] }, { "name": "Sendbird (Frankfurt)", "url": "https://status-frankfurt.sendbird.com/", "id": "qt3xhnxvn2sw", "subservice": true, "old_names": [ "SendbirdFrankfurt" ] }, { "name": "Sendbird (Mumbai)", "url": "https://status-mumbai.sendbird.com/", "id": "sng1ltdy77pf", "subservice": true, "old_names": [ "SendbirdMumbai" ] }, { "name": "Sendbird (North Virginia 2)", "url": "https://status-nvirginia2.sendbird.com/", "id": "nwc3tc3ghc55", "subservice": true, "old_names": [ "SendbirdNorthVirginia2" ] }, { "name": "Sendbird (North Virginia)", "url": "https://status-nvirginia1.sendbird.com/", "id": "xlrzypr8w8p5", "subservice": true, "old_names": [ "SendbirdNorthVirginia" ] }, { "name": "Sendbird (Oregon)", "url": "https://status-oregon.sendbird.com/", "id": "phbv0js99n45", "subservice": true, "old_names": [ "SendbirdOregon" ] }, { "name": "Sendbird (Seoul)", "url": "https://status-seoul.sendbird.com/", "id": "6r983tc47nw4", "subservice": true, "old_names": [ "SendbirdSeoul" ] }, { "name": "Sendbird (Singapore 2)", "url": "https://status-singapore2.sendbird.com/", "id": "2knm7ggfmh3s", "subservice": true, "old_names": [ "SendbirdSingapore2" ] }, { "name": "Sendbird (Singapore)", "url": "https://status-singapore.sendbird.com/", "id": "phbv0js99n45", "subservice": true, "old_names": [ "SendbirdSingapore" ] }, { "name": "Sendbird (Sydney)", "url": "https://status-sydney.sendbird.com/", "id": "dy9hbf5scsg1", "subservice": true, "old_names": [ "SendbirdSydney" ] }, { "name": "Sendbird (Tokyo)", "url": "https://status-tokyo.sendbird.com/", "id": "rfx6f11vcjtc", "subservice": true, "old_names": [ "SendbirdTokyo" ] } ] } ================================================ FILE: Scripts/generate_adobe_services.swift ================================================ #!/usr/bin/swift import Foundation struct Cloud { let id: String let name: String let products: [Product] init?(dictionary: [String: Any], productsMap: [String: Product]) { guard let id = dictionary["id"] as? String, let name = dictionary["name"] as? String, let productIDs = dictionary["cloudProducts"] as? [String] else { return nil } self.id = id self.name = name products = productIDs.compactMap { productsMap[$0] } } } struct Product { let id: String let name: String init?(dictionary: [String: Any]) { guard let id = dictionary["id"] as? String, let name = dictionary["name"] as? String else { return nil } self.id = id self.name = name } } struct AdobeService { enum ServiceType { case category case service case subService } let id: String let parentName: String let name: String let type: ServiceType var className: String { var sanitizedName = name sanitizedName = sanitizedName.replacingOccurrences(of: " & ", with: "And") sanitizedName = sanitizedName.replacingOccurrences(of: "/", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: ":", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: "-", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: ".", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: "(", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: ")", with: "") return sanitizedName .components(separatedBy: " ") .map { $0.capitalized(firstLetterOnly: true) } .joined(separator: "") } init(id: String, parentName: String, name: String, type: ServiceType) { self.id = id self.parentName = parentName self.type = type if !name.hasPrefix("Adobe") { self.name = "Adobe \(name)" } else { self.name = name } } var output: String { switch type { case .category: return """ final class \(className)All: \(className), ServiceCategory { let categoryName = "\(name)" let subServiceSuperclass: AnyObject.Type = Base\(className).self let name = "\(name) (All)" let id = "\(id)" } """ case .service: return """ final class \(className): \(parentName) { let name = "\(name)" let id = "\(id)" } """ case .subService: return """ final class \(className): \(parentName), SubService { let name = "\(name)" let id = "\(id)" } """ } } } extension String { func capitalized(firstLetterOnly: Bool) -> String { return firstLetterOnly ? (prefix(1).capitalized + dropFirst()) : self } } func envVariable(forKey key: String) -> String { guard let variable = ProcessInfo.processInfo.environment[key] else { print("error: Environment variable '\(key)' not set") exit(1) } return variable } func discoverServices() -> [AdobeService] { var dataResult: Data? let semaphore = DispatchSemaphore(value: 0) let url = URL(string: "https://data.status.adobe.com/adobestatus/SnowServiceRegistry")! URLSession.shared.dataTask(with: url) { data, _, _ in dataResult = data semaphore.signal() }.resume() _ = semaphore.wait(timeout: .now() + .seconds(10)) guard let data = dataResult, let structure = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { print("warning: Build script generate_adobe_services could not retrieve list of Adobe services") exit(0) } let productsDictionary = (structure["products"] as? [String: Any]) ?? [:] let productsMap = productsDictionary.compactMapValues { (value: Any) -> Product? in guard let dict = value as? [String: Any] else { return nil } return Product(dictionary: dict) } let cloudsDictionary = (structure["clouds"] as? [String: Any]) ?? [:] let clouds = cloudsDictionary.compactMap { (_, value) -> Cloud? in guard let dict = value as? [String: Any] else { return nil } return Cloud(dictionary: dict, productsMap: productsMap) } var uniqueNames = Set() // Create the categories from the clouds var categories = [String: AdobeService]() clouds.forEach { cloud in var name = cloud.name if uniqueNames.contains(name) { name = "\(name) (\(cloud.id))" } uniqueNames.insert(name) let category = AdobeService(id: cloud.id, parentName: "", name: name, type: .category) categories[cloud.id] = category // Create the subservices from the products cloud.products.forEach { product in var name = product.name if uniqueNames.contains(name) { name = "\(name) (\(product.id))" } uniqueNames.insert(name) let subService = AdobeService(id: product.id, parentName: category.className, name: name, type: .subService) categories[product.id] = subService } } let result: [AdobeService] = categories.values.sorted { $0.name.caseInsensitiveCompare($1.name) != .orderedDescending } return result } func main() { let srcRoot = envVariable(forKey: "SRCROOT") let outputPath = "\(srcRoot)/stts/Services/Generated/AdobeServices.swift" let services = discoverServices() let header = """ // This file is generated by generate_adobe_services.swift and should not be modified manually. // swiftlint:disable superfluous_disable_command type_name import Foundation """ let content = services.map { $0.output }.joined(separator: "\n\n") let footer = "" let output = [header, content, footer].joined(separator: "\n") // swiftlint:disable:next force_try try! output.write(toFile: outputPath, atomically: true, encoding: .utf8) print("Finished generating Adobe services.") } main() ================================================ FILE: Scripts/generate_apple_services.swift ================================================ #!/usr/bin/swift import Foundation private struct AppleResponseData: Codable { struct Service: Codable { let serviceName: String } let services: [Service] } struct AppleService { enum ServiceType { case category case subService } let parentName: String var name: String let serviceName: String let type: ServiceType var className: String { var sanitizedName = name sanitizedName = sanitizedName.replacingOccurrences(of: " & ", with: "And") sanitizedName = sanitizedName.replacingOccurrences(of: "/", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: ":", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: "-", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: ".", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: "(", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: ")", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: "+", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: ",", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: "|", with: "") return sanitizedName .components(separatedBy: " ") .map { $0.capitalized(firstLetterOnly: true) } .joined(separator: "") } init(parentName: String, name: String, type: ServiceType) { self.parentName = parentName self.type = type self.serviceName = name if !name.hasPrefix("Apple") { self.name = "Apple \(name)" } else { self.name = name } } var output: String { switch type { case .category: return """ final class \(className)All: \(className), ServiceCategory { let categoryName = "\(name)" let subServiceSuperclass: AnyObject.Type = Base\(className).self let name = "\(name) (All)" let serviceName = "*" } """ case .subService: return """ final class \(className): \(parentName), SubService { let name = "\(name)" let serviceName = "\(serviceName)" } """ } } } extension String { func capitalized(firstLetterOnly: Bool) -> String { return firstLetterOnly ? (prefix(1).capitalized + dropFirst()) : self } var innerJSONString: String { let callbackPrefix = "jsonCallback(" let callbackSuffix = ");" let trimmedString = trimmingCharacters(in: .whitespacesAndNewlines) guard trimmedString.hasPrefix(callbackPrefix) && trimmedString.hasSuffix(callbackSuffix) else { return self } return String(trimmedString[ trimmedString.index(trimmedString.startIndex, offsetBy: callbackPrefix.count) ..< trimmedString.index(trimmedString.endIndex, offsetBy: -callbackSuffix.count) ]) } } func envVariable(forKey key: String) -> String { guard let variable = ProcessInfo.processInfo.environment[key] else { print("error: Environment variable '\(key)' not set") exit(1) } return variable } func discoverServices(url: String, categoryName: String, categoryClassName: String) -> [AppleService] { var dataResult: Data? let semaphore = DispatchSemaphore(value: 0) let url = URL(string: url)! URLSession.shared.dataTask(with: url) { data, _, _ in dataResult = data semaphore.signal() }.resume() _ = semaphore.wait(timeout: .now() + .seconds(10)) guard let data = dataResult, let jsonData = String(data: data, encoding: .utf8)?.innerJSONString.data(using: .utf8), let responseData = try? JSONDecoder().decode(AppleResponseData.self, from: jsonData) else { print("warning: Build script generate_apple_services could not retrieve list of \(categoryName) services") exit(0) } let result: [AppleService] = [AppleService(parentName: "", name: categoryName, type: .category)] + responseData.services.map { AppleService(parentName: categoryClassName, name: $0.serviceName, type: .subService) } return result } func main() { let srcRoot = envVariable(forKey: "SRCROOT") let outputPath = "\(srcRoot)/stts/Services/Generated/AppleServices.swift" let services = discoverServices( url: "https://www.apple.com/support/systemstatus/data/system_status_en_US.js", categoryName: "Apple", categoryClassName: "Apple" ) var developerServices = discoverServices( url: "https://www.apple.com/support/systemstatus/data/developer/system_status_en_US.js", categoryName: "Apple Developer", categoryClassName: "AppleDeveloper" ) // Fix name collisions let serviceNames = services.map { $0.name } developerServices = developerServices.map { if serviceNames.contains($0.name) { var renamedService = $0 renamedService.name = "\($0.name) (Developer)" return renamedService } else { return $0 } } let header = """ // This file is generated by generate_apple_services.swift and should not be modified manually. // swiftlint:disable superfluous_disable_command type_name import Foundation """ let content = (services + developerServices).map { $0.output }.joined(separator: "\n\n") let footer = "" let output = [header, content, footer].joined(separator: "\n") // swiftlint:disable:next force_try try! output.write(toFile: outputPath, atomically: true, encoding: .utf8) print("Finished generating Apple services.") } main() ================================================ FILE: Scripts/generate_aws_services.swift ================================================ #!/usr/bin/swift import Foundation extension String { func capitalized(firstLetterOnly: Bool) -> String { return firstLetterOnly ? (prefix(1).capitalized + dropFirst()) : self } } func envVariable(forKey key: String) -> String { guard let variable = ProcessInfo.processInfo.environment[key] else { print("error: Environment variable '\(key)' not set") exit(1) } return variable } struct Service: Codable { enum CodingKeys: String, CodingKey { case id = "service" case name = "service_name" case regionName = "region_name" case regionID = "region_id" } let id: String let name: String let regionName: String? let regionID: String? } protocol OutputService { var output: String { get } var sortingName: String { get } } class OutputNamedService: OutputService { let name: String var ids = Set() var sortingName: String { usableName } var usableName: String { var result = name if !result.hasPrefix("Amazon "), !result.hasPrefix("AWS ") { result = "AWS \(name)" } return result } var className: String { var sanitizedName = usableName sanitizedName = sanitizedName.replacingOccurrences(of: " & ", with: "And") sanitizedName = sanitizedName.replacingOccurrences(of: "/", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: ":", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: "-", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: ".", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: "(", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: ")", with: "") return sanitizedName .components(separatedBy: " ") .map { $0.capitalized(firstLetterOnly: true) } .joined(separator: "") } var output: String { """ final class \(className): AWSNamedService, SubService { let name = "\(usableName)" let ids = Set([ "\(ids.sorted().joined(separator: "\",\n \""))" ]) } """ } init(initialService: Service) { name = initialService.name add(initialService) } func add(_ service: Service) { ids.insert(service.id) } } class OutputRegion: OutputService { let id: String let name: String var sortingName: String { "111\(usableName)" } var usableName: String { "AWS (\(name))" } var className: String { var sanitizedName = usableName sanitizedName = sanitizedName.replacingOccurrences(of: " & ", with: "And") sanitizedName = sanitizedName.replacingOccurrences(of: "/", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: ":", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: "-", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: ".", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: "(", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: ")", with: "") return sanitizedName .components(separatedBy: " ") .map { $0.capitalized(firstLetterOnly: true) } .joined(separator: "") } var output: String { """ final class \(className): AWSRegionService, SubService { let id = "\(id)" let name = "\(usableName)" } """ } init(id: String, name: String) { self.id = id self.name = name } } func discoverServices() -> [OutputService] { var dataResult: Data? let semaphore = DispatchSemaphore(value: 0) let url = URL(string: "https://d3s31nlw3sm5l8.cloudfront.net/services.json")! URLSession.shared.dataTask(with: url) { data, _, _ in dataResult = data semaphore.signal() }.resume() _ = semaphore.wait(timeout: .now() + .seconds(10)) guard let data = dataResult, let services = try? JSONDecoder().decode([Service].self, from: data) else { print("warning: Build script generate_aws_services could not retrieve list of AWS services") exit(0) } var servicesByName: [String: OutputNamedService] = [:] var regions: [String: OutputRegion] = [:] services.forEach { let namedService = servicesByName[$0.name] ?? OutputNamedService(initialService: $0) namedService.add($0) servicesByName[$0.name] = namedService if let regionID = $0.regionID, let regionName = $0.regionName { if regions[regionID] == nil { regions[regionID] = OutputRegion(id: regionID, name: regionName) } } } let namedServices: [OutputService] = [OutputNamedService](servicesByName.values) let regionServices: [OutputService] = [OutputRegion](regions.values) return namedServices + regionServices } func main() { let srcRoot = envVariable(forKey: "SRCROOT") let outputPath = "\(srcRoot)/stts/Services/Generated/AWSServices.swift" let services = discoverServices() let header = """ // This file is generated by generate_aws_services.swift and should not be modified manually. // swiftlint:disable superfluous_disable_command type_name import Foundation final class AWSRegions: AWSAllService, ServiceCategory { let categoryName = "Amazon Web Services (by region)" let subServiceSuperclass: AnyObject.Type = BaseAWSRegionService.self let name = "AWS Regions (All)" } final class AWSServices: AWSAllService, ServiceCategory { let categoryName = "Amazon Web Services" let subServiceSuperclass: AnyObject.Type = BaseAWSNamedService.self let name = "AWS (All)" } """ let content = services.sorted(by: { one, two in one.sortingName < two.sortingName }).map { $0.output }.joined(separator: "\n\n") let footer = "" let output = [header, content, footer].joined(separator: "\n") debugPrint(output) // swiftlint:disable:next force_try try! output.write(toFile: outputPath, atomically: true, encoding: .utf8) print("Finished generating AWS services.") } main() ================================================ FILE: Scripts/generate_azure_devops_services.swift ================================================ #!/usr/bin/swift import Foundation struct AzureDevOpsService { let serviceName: String var friendlyName: String { let friendlyServiceName = serviceName.components(separatedBy: " ").map { $0.capitalized(firstLetterOnly: true) }.joined(separator: " ") return "Azure DevOps \(friendlyServiceName)" } var className: String { var sanitizedName = serviceName sanitizedName = sanitizedName.replacingOccurrences(of: " & ", with: "And") sanitizedName = sanitizedName.replacingOccurrences(of: "/", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: ":", with: "") sanitizedName = sanitizedName.components(separatedBy: " ") .map { $0.capitalized(firstLetterOnly: true) } .joined(separator: "") return "AzureDevOps\(sanitizedName)" } var output: String { return """ final class \(className): AzureDevOps, SubService { let name = "\(friendlyName)" let serviceName = "\(serviceName)" } """ } } extension String { subscript(_ range: NSRange) -> String { // Why we still have to do this shit in 2019 I don't know let start = self.index(self.startIndex, offsetBy: range.lowerBound) let end = self.index(self.startIndex, offsetBy: range.upperBound) let subString = self[start.. String { return firstLetterOnly ? (prefix(1).capitalized + dropFirst()) : self } } struct AzureDevOpsDataProviders: Codable { struct ResponseData: Codable { struct MetadataProvider: Codable { let services: [[String: String]] var serviceNames: [String] { return services.compactMap { $0["id"] } } } enum CodingKeys: String, CodingKey { case metadataProvider = "ms.vss-status-web.public-status-metadata-data-provider" } let metadataProvider: MetadataProvider } let data: ResponseData } func envVariable(forKey key: String) -> String { guard let variable = ProcessInfo.processInfo.environment[key] else { print("error: Environment variable '\(key)' not set") exit(1) } return variable } func discoverServices() -> [AzureDevOpsService] { var result = [AzureDevOpsService]() var dataResult: Data? let semaphore = DispatchSemaphore(value: 0) URLSession.shared.dataTask(with: URL(string: "https://status.dev.azure.com")!) { data, _, _ in dataResult = data semaphore.signal() }.resume() _ = semaphore.wait(timeout: .now() + .seconds(10)) guard let data = dataResult, let body = String(data: data, encoding: .utf8) as NSString? else { print("warning: Build script generate_azure_devops_services could not retrieve list of Azure DevOps services") exit(0) } // swiftlint:disable:next force_try let regex = try! NSRegularExpression( pattern: "", options: [.caseInsensitive, .dotMatchesLineSeparators] ) let range = NSRange(location: 0, length: body.length) regex.enumerateMatches(in: body as String, options: [], range: range) { textCheckingResult, _, _ in guard let textCheckingResult = textCheckingResult, textCheckingResult.numberOfRanges == 2 else { return } let json = body.substring(with: textCheckingResult.range(at: 1)) let jsonData = json.data(using: .utf8)! guard let decodedProviders = try? JSONDecoder().decode(AzureDevOpsDataProviders.self, from: jsonData) else { print( "warning: Build script generate_azure_devops_services could not retrieve list of Azure DevOps services" ) exit(0) } decodedProviders.data.metadataProvider.serviceNames.forEach { result.append(AzureDevOpsService(serviceName: $0)) } } return result } func main() { let srcRoot = envVariable(forKey: "SRCROOT") let outputPath = "\(srcRoot)/stts/Services/Generated/AzureDevOpsServices.swift" let services = discoverServices() let header = """ // This file is generated by generate_azure_devops_services.swift and should not be modified manually. // swiftlint:disable superfluous_disable_command type_name import Foundation """ let content = services.map { $0.output }.joined(separator: "\n\n") let footer = "" let output = [header, content, footer].joined(separator: "\n") // swiftlint:disable:next force_try try! output.write(toFile: outputPath, atomically: true, encoding: .utf8) print("Finished generating Azure DevOps services.") } main() ================================================ FILE: Scripts/generate_azure_services.swift ================================================ #!/usr/bin/swift import Foundation struct AzureZone { let serviceName: String let zoneIdentifier: String var className: String { var sanitizedName = serviceName sanitizedName = sanitizedName.replacingOccurrences(of: " & ", with: "And") sanitizedName = sanitizedName.replacingOccurrences(of: "/", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: ":", with: "") return sanitizedName.components(separatedBy: " ") .map { $0.capitalized(firstLetterOnly: true) } .joined(separator: "") } init(identifier: String, serviceName: String) { zoneIdentifier = identifier if !serviceName.hasPrefix("Azure") { self.serviceName = "Azure \(serviceName)" } else { self.serviceName = serviceName } } var output: String { return """ final class \(className): Azure, SubService { let name = "\(serviceName)" let zoneIdentifier = "\(zoneIdentifier)" } """ } } extension String { subscript(_ range: NSRange) -> String { // Why we still have to do this shit in 2019 I don't know let start = self.index(self.startIndex, offsetBy: range.lowerBound) let end = self.index(self.startIndex, offsetBy: range.upperBound) let subString = self[start.. String { return firstLetterOnly ? (prefix(1).capitalized + dropFirst()) : self } } func envVariable(forKey key: String) -> String { guard let variable = ProcessInfo.processInfo.environment[key] else { print("error: Environment variable '\(key)' not set") exit(1) } return variable } func discoverZones() -> [AzureZone] { var result = [AzureZone]() var dataResult: Data? let semaphore = DispatchSemaphore(value: 0) URLSession.shared.dataTask(with: URL(string: "https://status.azure.com/en-us/status")!) { data, _, _ in dataResult = data semaphore.signal() }.resume() _ = semaphore.wait(timeout: .now() + .seconds(10)) guard let data = dataResult, var body = String(data: data, encoding: .utf8) else { print("warning: Build script generate_azure_services could not retrieve list of Azure zones") exit(0) } body = body.replacingOccurrences(of: "\n", with: "") // swiftlint:disable:next force_try let regex = try! NSRegularExpression( pattern: "li role=\"presentation\".*?data-zone-name=\"(.*?)\".*?data-event-property=\"(.*?)\"", options: [.caseInsensitive, .dotMatchesLineSeparators] ) // Some tabs in the Azure status website do not correspond to actual zones, so we exclude them let excludedZoneIdentifiers = Set(["current-impact"]) let range = NSRange(location: 0, length: body.count) regex.enumerateMatches(in: body, options: [], range: range) { textCheckingResult, _, _ in guard let textCheckingResult = textCheckingResult, textCheckingResult.numberOfRanges == 3 else { return } let identifier = body[textCheckingResult.range(at: 1)] let serviceName = body[textCheckingResult.range(at: 2)] if excludedZoneIdentifiers.contains(identifier) == false { result.append(AzureZone(identifier: identifier, serviceName: serviceName)) } } return result } func main() { let srcRoot = envVariable(forKey: "SRCROOT") let outputPath = "\(srcRoot)/stts/Services/Generated/AzureServices.swift" let zones = discoverZones() let header = """ // This file is generated by generate_azure_services.swift and should not be modified manually. // swiftlint:disable superfluous_disable_command type_name import Foundation """ let content = zones.map { $0.output }.joined(separator: "\n\n") let footer = "" let output = [header, content, footer].joined(separator: "\n") // swiftlint:disable:next force_try try! output.write(toFile: outputPath, atomically: true, encoding: .utf8) print("Finished generating Azure services.") } main() ================================================ FILE: Scripts/generate_google_services.swift ================================================ #!/usr/bin/swift import Foundation enum GooglePlatform: CaseIterable { case cloudPlatform case firebase var url: URL { switch self { case .cloudPlatform: // swiftlint:disable:next force_unwrapping return URL(string: "https://status.cloud.google.com")! case .firebase: // swiftlint:disable:next force_unwrapping return URL(string: "https://status.firebase.google.com")! } } func outputPath(root: String) -> String { switch self { case .cloudPlatform: return "\(root)/stts/Services/Generated/GoogleCloudPlatformServices.swift" case .firebase: return "\(root)/stts/Services/Generated/FirebaseServices.swift" } } } protocol Service { var serviceName: String { get } var className: String { get } var output: String { get } } extension Service { var className: String { var sanitizedName = serviceName sanitizedName = sanitizedName.replacingOccurrences(of: " & ", with: "And") sanitizedName = sanitizedName.replacingOccurrences(of: "/", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: ":", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: "-", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: "(", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: ")", with: "") return sanitizedName.components(separatedBy: " ") .map { $0.capitalized(firstLetterOnly: true) } .joined(separator: "") } } struct GCPService: Service { let serviceName: String let dashboardName: String init(dashboardName: String) { self.dashboardName = dashboardName if !dashboardName.hasPrefix("Google") { serviceName = "Google \(dashboardName)" } else { serviceName = dashboardName } } var output: String { return """ final class \(className): GoogleCloudPlatform, SubService { let name = "\(serviceName)" let dashboardName = "\(dashboardName)" } """ } } struct FirebaseService: Service { let serviceName: String init(dashboardName: String) { if !dashboardName.hasPrefix("Firebase") { serviceName = "Firebase \(dashboardName)" } else { serviceName = dashboardName } } var output: String { return """ final class \(className): FirebaseService, SubService { let name = "\(serviceName)" } """ } } extension String { subscript(_ range: NSRange) -> String { // Why we still have to do this shit in 2019 I don't know let start = self.index(self.startIndex, offsetBy: range.lowerBound) let end = self.index(self.startIndex, offsetBy: range.upperBound) let subString = self[start.. String { return firstLetterOnly ? (prefix(1).capitalized + dropFirst()) : self } } func envVariable(forKey key: String) -> String { guard let variable = ProcessInfo.processInfo.environment[key] else { print("error: Environment variable '\(key)' not set") exit(1) } return variable } func discoverServices(for platform: GooglePlatform) -> [Service] { var result = [Service]() var dataResult: Data? let semaphore = DispatchSemaphore(value: 0) URLSession.shared.dataTask(with: platform.url) { data, _, _ in dataResult = data semaphore.signal() }.resume() _ = semaphore.wait(timeout: .now() + .seconds(10)) guard let data = dataResult, var body = String(data: data, encoding: .utf8) else { print(""" warning: Build script generate_google_services could not retrieve list of Google Cloud Platform/Firebase services """) exit(0) } body = body.replacingOccurrences(of: "\n", with: "") let regex: NSRegularExpression switch platform { case .cloudPlatform: // swiftlint:disable:next force_try regex = try! NSRegularExpression( pattern: "__product\">[\\s\\n]*(.+?)[\\s\\n]*<.*?\\/th>", options: [.caseInsensitive, .dotMatchesLineSeparators] ) case .firebase: // swiftlint:disable:next force_try regex = try! NSRegularExpression( pattern: "class=\"product-name\">.*?[\\s\\n]*([^>]*?)[\\s\\n]*<\\/", options: [.caseInsensitive, .dotMatchesLineSeparators] ) } let range = NSRange(location: 0, length: body.count) regex.enumerateMatches(in: body, options: [], range: range) { textCheckingResult, _, _ in guard let textCheckingResult = textCheckingResult, textCheckingResult.numberOfRanges == 2 else { return } let serviceName = body[textCheckingResult.range(at: 1)] switch platform { case .cloudPlatform: result.append(GCPService(dashboardName: serviceName)) case .firebase: result.append(FirebaseService(dashboardName: serviceName)) } } return result } func main() { let srcRoot = envVariable(forKey: "SRCROOT") GooglePlatform.allCases.forEach { platform in let services = discoverServices(for: platform) let header = """ // This file is generated by generate_google_services.swift and should not be modified manually. // swiftlint:disable superfluous_disable_command type_name import Foundation """ let content = services.map { $0.output }.joined(separator: "\n\n") let footer = "" let output = [header, content, footer].joined(separator: "\n") // swiftlint:disable:next force_try try! output.write(toFile: platform.outputPath(root: srcRoot), atomically: true, encoding: .utf8) } print("Finished generating Google services.") } main() ================================================ FILE: Scripts/generate_salesforce_services.swift ================================================ #!/usr/bin/swift import Foundation enum Location: String { case na = "NA" case emea = "EMEA" case apac = "APAC" case all = "ALL" var suffix: String { switch self { case .na, .emea, .apac: return "(\(rawValue))" case .all: return "(All Regions)" } } var classFormat: String { switch self { case .na, .emea, .apac: return rawValue case .all: return "All" } } var appFormat: String { switch self { case .na, .emea, .apac: return rawValue case .all: return "*" } } } struct SalesforceProductRegion { let name: String let key: String let location: Location var className: String { var sanitizedName = name sanitizedName = sanitizedName.replacingOccurrences(of: " & ", with: "And") sanitizedName = sanitizedName.replacingOccurrences(of: "/", with: "") sanitizedName = sanitizedName.replacingOccurrences(of: ":", with: "") return sanitizedName.components(separatedBy: " ") .map { $0.capitalized(firstLetterOnly: true) } .joined(separator: "") } var classNameWithRegion: String { "\(className) \(location.classFormat)" .components(separatedBy: " ") .map { $0.capitalized(firstLetterOnly: true) } .joined(separator: "") } var serviceName: String { "\(name) \(location.suffix)" } init(key: String, location: Location) { self.key = key self.location = location switch key { case "Salesforce_Services": name = "Salesforce Services" case "Marketing_Cloud": name = "Salesforce Marketing Cloud" case "B2C_Commerce_Cloud": name = "Salesforce B2C Commerce Cloud" case "Social_Studio": name = "Salesforce Social Studio" case "Community_Cloud": name = "Salesforce Experience Cloud" default: // Keep it instead of failing so that we notice when new products are added. name = key } } var superOutput: String { """ typealias \(className) = Base\(className) & RequiredServiceProperties & SalesforceStoreService class Base\(className): BaseSalesforceCategory { static var store = SalesforceStore(key: "\(key)") let url = URL(string: "https://status.salesforce.com/products/\(key)")! } """ } var output: String { let commonDefinitions: [String] = [ "let name = \"\(serviceName)\"", "let key = \"\(key)\"", "let location = \"\(location.appFormat)\"" ] if location == .all { return """ final class \(classNameWithRegion): \(className), ServiceCategory { let categoryName = "\(name)" let subServiceSuperclass: AnyObject.Type = Base\(className).self \(commonDefinitions.joined(separator: "\n ")) } """ } else { return """ final class \(classNameWithRegion): \(className), SubService { \(commonDefinitions.joined(separator: "\n ")) } """ } } } struct Instance: Codable { enum CodingKeys: String, CodingKey { case location case products = "Products" } let location: String let products: [Product] } struct Product: Codable { let key: String } extension String { func capitalized(firstLetterOnly: Bool) -> String { return firstLetterOnly ? (prefix(1).capitalized + dropFirst()) : self } } func envVariable(forKey key: String) -> String { guard let variable = ProcessInfo.processInfo.environment[key] else { print("error: Environment variable '\(key)' not set") exit(1) } return variable } func discoverProducts() -> [SalesforceProductRegion] { var result = [SalesforceProductRegion]() var dataResult: Data? let semaphore = DispatchSemaphore(value: 0) let url = URL(string: "https://api.status.salesforce.com/v1/instances?childProducts=false")! URLSession.shared.dataTask(with: url) { data, _, _ in dataResult = data semaphore.signal() }.resume() _ = semaphore.wait(timeout: .now() + .seconds(10)) guard let data = dataResult, let instances = try? JSONDecoder().decode([Instance].self, from: data) else { print("warning: Build script generate_salesforce_services could not retrieve list of Salesforce products") exit(0) } var productsSet = Set() var productsAndRegions: [String: Set] = [:] instances.forEach { guard let product = $0.products.first else { return } var regions = productsAndRegions[product.key] ?? Set() regions.insert($0.location) productsAndRegions[product.key] = regions productsSet.insert(product.key) } let sortedProducts = productsSet.sorted() sortedProducts.forEach { productKey in result.append(SalesforceProductRegion(key: productKey, location: .all)) productsAndRegions[productKey]?.sorted().forEach { guard let location = Location(rawValue: $0) else { return } result.append(SalesforceProductRegion(key: productKey, location: location)) } } return result } func generateProducts(from products: [SalesforceProductRegion]) { let srcRoot = envVariable(forKey: "SRCROOT") let outputPath = "\(srcRoot)/stts/Services/Generated/SalesforceProducts.swift" let header = """ // This file is generated by generate_salesforce_services.swift and should not be modified manually. // swiftlint:disable superfluous_disable_command type_name import Foundation """ let content = products.map { $0.output }.joined(separator: "\n\n") let footer = "" let output = [header, content, footer].joined(separator: "\n") // swiftlint:disable:next force_try try! output.write(toFile: outputPath, atomically: true, encoding: .utf8) } func generateSuper(from products: [SalesforceProductRegion]) { let srcRoot = envVariable(forKey: "SRCROOT") let outputPath = "\(srcRoot)/stts/Services/Super/SalesforceCategories.swift" let header = """ // This file is generated by generate_salesforce_services.swift and should not be modified manually. // swiftlint:disable superfluous_disable_command type_name import Foundation """ let content = products.filter { $0.location == .all }.map { $0.superOutput }.joined(separator: "\n\n") let footer = "" let output = [header, content, footer].joined(separator: "\n") // swiftlint:disable:next force_try try! output.write(toFile: outputPath, atomically: true, encoding: .utf8) } func main() { let products = discoverProducts() generateProducts(from: products) generateSuper(from: products) print("Finished generating Salesforce services.") } main() ================================================ FILE: Scripts/generate_services_plist.sh ================================================ #!/bin/sh RESOURCES_PATH="$BUILT_PRODUCTS_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH" SERVICES_PLIST="$RESOURCES_PATH/services.plist" # Retrieve the list of services REGULAR_SERVICES=$(find "$SRCROOT/stts/Services" -name "*.swift" -not -path "*Super*" -not -path "*Generated*" | awk -F/ '{ print $NF }' | sed s/.swift//g | sort | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g') GENERATED_SERVICES=$(find "$SRCROOT/stts/Services/Generated" -name "*.swift" -print0 | xargs -0 cat | grep "class " | sed s/'final class '//g | sed s/'class '//g | sed 's/:.*//' | tr '\n' ' ') SERVICES="$REGULAR_SERVICES $GENERATED_SERVICES" # Create the services plist file echo "{}" > "$SERVICES_PLIST" # Write the list of services into the plist file as an array defaults write "$SERVICES_PLIST" "services" -array $SERVICES # Remove all quarantine attributes as they block submissions to App Store xattr -c "$SERVICES_PLIST" ================================================ FILE: extract.rb ================================================ require 'net/https' require 'xcodeproj' require 'json' require 'synx' @project_file = "stts.xcodeproj" def source_for(url) uri = URI.parse(url) path = uri.path == "" ? "/" : uri.path result = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') { |http| http.get(path) } result.code.to_i == 200 ? result.body : nil end def extract_instatus(source, custom_name) data = source.scan(/__NEXT_DATA__.*?(\{.*?\})<\/script>/mi).flatten.first return false if data == nil || data.empty? site = JSON.parse(data)["props"]["pageProps"]["site"] custom_domain = site["customDomain"] if custom_domain && custom_domain != "" domain = custom_domain else domain = "#{site["subdomain"]}.instatus.com" end name = custom_name || site["name"] url = "https://#{domain}" safe_name = sanitized_name(name) definitions = [ "let url = URL(string: \"#{url}\")!" ] definitions.unshift("let name = \"#{name}\"") if safe_name != name create_file "stts/Services/Instatus/#{safe_name}.swift", <<-INSTATUS // // #{safe_name}.swift // stts // import Foundation class #{safe_name}: InstatusService { #{definitions.join("\n ")} } INSTATUS return true end def extract_statuspage(url, custom_name) source = source_for("#{url}/api/v2/summary.json") return false unless source page = JSON.parse(source)["page"] id = page["id"] name = custom_name || page["name"] safe_name = sanitized_name(name) definitions = [ "let url = URL(string: \"#{url}\")!", "let statusPageID = \"#{id}\"" ] definitions.unshift("let name = \"#{name}\"") if safe_name != name create_file "stts/Services/StatusPage/#{safe_name}.swift", <<-STATUSPAGE // // #{safe_name}.swift // stts // import Foundation class #{safe_name}: StatusPageService { #{definitions.join("\n ")} } STATUSPAGE true end def extract_site24x7(url, source, custom_name) encrypted_status_page_id = source.scan(/"enc_statuspage_id":.*?"(.*?)"/mi).flatten.first return false if encrypted_status_page_id == nil || encrypted_status_page_id.empty? if custom_name == nil || custom_name.empty? puts "Site24x7 service detected! Please provide the service name since it cannot be automatically found." puts puts "Usage:" puts "bundle exec ruby extract.rb " exit(1) end id = encrypted_status_page_id safe_name = sanitized_name(custom_name) definitions = [ "let url = URL(string: \"#{url}\")!", "let encryptedStatusPageID = \"#{id}\"" ] definitions.unshift("let name = \"#{custom_name}\"") if safe_name != custom_name create_file "stts/Services/Site24x7/#{safe_name}.swift", <<-SITE24X7 // // #{safe_name}.swift // stts // import Foundation class #{safe_name}: Site24x7Service { #{definitions.join("\n ")} } SITE24X7 true end def extract_cstate(url, custom_name) source = source_for("#{url}/index.json") return false unless source data = JSON.parse(source) return false unless data["cStateVersion"] != nil name = custom_name || better_name(data["title"]) base_url = data["baseURL"] || url safe_name = sanitized_name(name) definitions = [ "let url = URL(string: \"#{base_url}\")!" ] definitions.unshift("let name = \"#{name}\"") if safe_name != name create_file "stts/Services/CState/#{safe_name}.swift", <<-CSTATE // // #{safe_name}.swift // stts // import Foundation class #{safe_name}: CStateService { #{definitions.join("\n ")} } CSTATE true end def create_file(path, content) File.open(path, "w") do |f| f.write(content) end puts "Updated #{path}" # Open the existing Xcode project project = Xcodeproj::Project.open(@project_file) # Add a file to the project file_name = path.split("/").last group = project.main_group path.split("/")[0..-2].each do |group_name| group = group[group_name] if group[group_name] end if group.files.map(&:path).include?(file_name) puts "Skipped adding #{file_name} to project: already exists" return end # Get the file reference for the file to add file = group.new_file(file_name) # Add the file reference to the target main_target = project.targets.first main_target.add_file_references([file]) # Sort it project.main_group.sort_recursively_by_type # Save it project.save puts "Added #{file_name} to project" end def better_name(name) name.gsub(/(\'|\‘)?\sstatus$/i, "") end def sanitized_name(name) new_name = name.gsub(" & ", "And") .gsub("/", "") .gsub(":", "") .gsub("-", "") .gsub(".", "") .gsub("(", "") .gsub(")", "") .gsub("+", "") .gsub(",", "") .gsub(/(\'|\‘)?\sstatus$/i, "") words = new_name.split(" ").map do |word| # capitalize, first character only (CamelCase) word[0].upcase + word[1..-1] end words.join("") end def finish puts "Done!" puts "Running synx..." run_synx exit end def fail_params puts "Usage:" puts "bundle exec ruby extract.rb " puts puts "Example:" puts "bundle exec ruby extract.rb https://status.notion.so/" exit 1 end def fail_network puts "Could not check that link :(" puts "Network issue or invalid link?" exit 1 end def fail puts "No service found :(" puts "Maybe create a ticket? https://github.com/inket/stts/issues" exit 1 end def run_synx project = Synx::Project.open(@project_file) project.sync( prune: true, quiet: true, no_color: false, no_default_exclusions: false, no_sort_by_name: false, group_exclusions: [] ) end if Process.uid == 0 puts "Cannot run extract script as root.".red exit 1 end url = ARGV[0] url = url.strip if url fail_params unless url && url != "" custom_name = ARGV[1] custom_name = custom_name.strip if custom_name custom_name = nil if custom_name == "" url = "https://#{url}" if URI.parse(url).scheme == nil source = source_for(url) fail_network unless source finish if extract_instatus(source, custom_name) finish if extract_site24x7(url, source, custom_name) finish if extract_statuspage(url, custom_name) finish if extract_cstate(url, custom_name) fail ================================================ FILE: openai.html ================================================ OpenAI Status

OpenAI

System status

APIs

ChatGPT

Sora

FedRAMP

Powered by

Availability metrics are reported at an aggregate level across all tiers, models and error types. Individual customer availability may vary depending on their subscription tier as well as the specific model and API features in use.

================================================ FILE: sort.rb ================================================ require 'xcodeproj' # Open the existing Xcode project project_file = "stts.xcodeproj" project = Xcodeproj::Project.open(project_file) # Sort the main group (recursive) project.main_group.sort_recursively_by_type # Save project.save ================================================ FILE: stts/AppDelegate.swift ================================================ // // AppDelegate.swift // stts // import Cocoa import MBPopup import PreferencesWindow import Reachability @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate { private var shouldAutomaticallyCheckServices: Bool { // We don't want to start the updating timer when unit testing because: // 1. It will be checking services unnecessarily // 2. It will check services that have a Store (like Adobe) before our tests and cache statuses return ProcessInfo.processInfo.environment["UNIT_TESTING"] == nil } private var timer: Timer? private let reachability = try! Reachability() // swiftlint:disable:this force_try private var initialReachabilityChange: Bool = true let popupController: MBPopupController private let serviceTableViewController: ServiceTableViewController private let serviceLoader: ServiceLoader private let preferences: Preferences private let preferencesWindow: PreferencesWindow override init() { var serviceDefinitionProviders: [ServiceDefinitionProvider] = [] // swiftlint:disable:next force_try serviceDefinitionProviders.append(try! AppDefinedServiceDefinitionProvider()) // swiftlint:disable:next force_try serviceDefinitionProviders.append(try! BundleServiceDefinitionProvider()) if let userDefinedProvider = try? UserDefinedServiceDefinitionProvider() { serviceDefinitionProviders.append(userDefinedProvider) } serviceLoader = ServiceLoader(providers: serviceDefinitionProviders) SendbirdAll.sendbirdServices = serviceLoader.allServices .compactMap { $0 as? SendbirdServiceDefinition } .compactMap { $0.build() as? SendbirdService } preferences = Preferences(serviceLoader: serviceLoader) preferencesWindow = PreferencesWindow(serviceLoader: serviceLoader, preferences: preferences) serviceTableViewController = ServiceTableViewController( serviceLoader: serviceLoader, preferences: preferences, preferencesWindow: preferencesWindow ) popupController = MBPopupController(contentView: serviceTableViewController.contentView) } func applicationDidFinishLaunching(_ aNotification: Notification) { NSWorkspace.shared.notificationCenter.addObserver( self, selector: #selector(AppDelegate.restartTimer), name: NSWorkspace.didWakeNotification, object: nil ) if shouldAutomaticallyCheckServices { reachability.whenReachable = { [weak self] _ in self?.reachabilityChanged() } reachability.whenUnreachable = { [weak self] _ in self?.reachabilityChanged() } } try? reachability.startNotifier() Appearance.addObserver(self) NSUserNotificationCenter.default.delegate = self popupController.statusItem.button?.title = "stts" popupController.statusItem.button?.font = NSFont(name: "SF Mono Regular", size: 10) ?? NSFont.systemFont(ofSize: 12) popupController.statusItem.length = 30 popupController.contentView.wantsLayer = true popupController.contentView.layer?.masksToBounds = true serviceTableViewController.setup() preferencesWindow.saveCallback = { [weak self] in self?.serviceTableViewController.reloadServicesList() self?.updateServices() } popupController.willOpenPopup = { [weak self] _ in self?.serviceTableViewController.willOpenPopup() } if shouldAutomaticallyCheckServices { restartTimer() } } @objc private func restartTimer() { timer?.invalidate() timer = Timer.scheduledTimer( timeInterval: 300, target: self, selector: #selector(AppDelegate.updateServices), userInfo: nil, repeats: true ) timer?.fire() } @objc func updateServices() { serviceTableViewController.updateServices { [weak self] in guard let self else { return } let title = serviceTableViewController.generalStatus == .major ? "s__s" : "stts" popupController.statusItem.button?.title = title if preferences.notifyOnStatusChange { serviceTableViewController.services.forEach { $0.notifyIfStatusChanged() } } } } private func reachabilityChanged() { if initialReachabilityChange { // Reachability notifies us of a change on app launch (after calling startNotifier()), // we don't need it because it causes duplicate updateServices() initialReachabilityChange = false } else { updateServices() } } } extension AppDelegate: NSUserNotificationCenterDelegate { func userNotificationCenter(_ center: NSUserNotificationCenter, didActivate notification: NSUserNotification) { popupController.openPopup() } } extension AppDelegate: AppearanceObserver { func changeAppearance(to newAppearance: NSAppearance) { popupController.backgroundView.backgroundColor = newAppearance.isDarkMode ? .windowBackgroundColor : .white } } ================================================ FILE: stts/AppearanceObserver.swift ================================================ // // Appearance.swift // stts // import Cocoa protocol AppearanceObserver: AnyObject { func changeAppearance(to newAppearance: NSAppearance) } class Appearance { class Weak { fileprivate weak var object: AnyObject? init(_ object: AnyObject) { self.object = object } } private static var effectiveAppearanceObserver: Any? = { return NSApplication.shared.observe( \NSApplication.effectiveAppearance, options: [.new, .initial] ) { _, change in guard let newValue = change.newValue else { return } Appearance.fire(newAppearance: newValue) } }() private static var observers = [Weak]() private static func fire(newAppearance: NSAppearance) { observers = observers.filter { guard let object = $0.object else { return false } (object as? AppearanceObserver)?.changeAppearance(to: newAppearance) return true } } static func addObserver(_ observer: AppearanceObserver) { observers = observers.filter { $0.object != nil } observers.append(Weak(observer)) if effectiveAppearanceObserver == nil { fatalError("Did not setup appearance observer.") } } static func removeObserver(_ observer: AppearanceObserver) { observers = observers.filter { $0.object != nil && $0.object !== observer } } } extension NSAppearance { var isDarkMode: Bool { name == .darkAqua || name == .vibrantDark } } ================================================ FILE: stts/BottomBar.swift ================================================ // // BottomBar.swift // stts // import Cocoa enum BottomBarStatus { case undetermined case updating case updated(Date) } class BottomBar: NSView { let settingsButton = NSButton() let reloadButton = NSButton() let statusField = NSTextField() let separator = ServiceTableRowView() var status: BottomBarStatus = .undetermined { didSet { updateStatusText() } } var reloadServicesCallback: () -> Void = {} var openSettingsCallback: () -> Void = {} override init(frame frameRect: NSRect) { super.init(frame: frameRect) commonInit() } required init?(coder: NSCoder) { super.init(coder: coder) commonInit() } private func commonInit() { [separator, settingsButton, reloadButton, statusField].forEach { $0.translatesAutoresizingMaskIntoConstraints = false addSubview($0) } let gearIcon = GearIcon() gearIcon.translatesAutoresizingMaskIntoConstraints = false settingsButton.addSubview(gearIcon) let refreshIcon = RefreshIcon() refreshIcon.translatesAutoresizingMaskIntoConstraints = false reloadButton.addSubview(refreshIcon) NSLayoutConstraint.activate([ separator.heightAnchor.constraint(equalToConstant: 1), separator.topAnchor.constraint(equalTo: topAnchor), separator.leadingAnchor.constraint(equalTo: leadingAnchor), separator.trailingAnchor.constraint(equalTo: trailingAnchor), settingsButton.heightAnchor.constraint(equalToConstant: 30), settingsButton.widthAnchor.constraint(equalToConstant: 30), settingsButton.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 4), settingsButton.centerYAnchor.constraint(equalTo: centerYAnchor), gearIcon.centerYAnchor.constraint(equalTo: settingsButton.centerYAnchor), gearIcon.centerXAnchor.constraint(equalTo: settingsButton.centerXAnchor), gearIcon.heightAnchor.constraint(equalToConstant: 22), gearIcon.widthAnchor.constraint(equalToConstant: 22), reloadButton.heightAnchor.constraint(equalToConstant: 30), reloadButton.widthAnchor.constraint(equalToConstant: 30), reloadButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -4), reloadButton.centerYAnchor.constraint(equalTo: centerYAnchor), refreshIcon.centerYAnchor.constraint(equalTo: reloadButton.centerYAnchor), refreshIcon.centerXAnchor.constraint(equalTo: reloadButton.centerXAnchor), refreshIcon.heightAnchor.constraint(equalToConstant: 18), refreshIcon.widthAnchor.constraint(equalToConstant: 18), statusField.leadingAnchor.constraint(equalTo: settingsButton.trailingAnchor), statusField.trailingAnchor.constraint(equalTo: reloadButton.leadingAnchor), statusField.centerYAnchor.constraint(equalTo: centerYAnchor) ]) settingsButton.isBordered = false settingsButton.bezelStyle = .regularSquare settingsButton.title = "" settingsButton.target = self settingsButton.action = #selector(openSettings) gearIcon.scaleUnitSquare(to: NSSize(width: 0.46, height: 0.46)) reloadButton.isBordered = false reloadButton.bezelStyle = .regularSquare reloadButton.title = "" reloadButton.target = self reloadButton.action = #selector(reloadServices) refreshIcon.scaleUnitSquare(to: NSSize(width: 0.38, height: 0.38)) statusField.isEditable = false statusField.isBordered = false statusField.isSelectable = false let fontSize = NSFont.systemFontSize(for: .small) let font = NSFont.systemFont(ofSize: fontSize) let italicFont = NSFontManager.shared.font( withFamily: font.fontName, traits: NSFontTraitMask.italicFontMask, weight: 5, size: fontSize ) statusField.font = italicFont statusField.textColor = NSColor.secondaryLabelColor statusField.maximumNumberOfLines = 1 statusField.backgroundColor = NSColor.clear statusField.alignment = .center statusField.cell?.truncatesLastVisibleLine = true } func updateStatusText() { switch status { case .undetermined: statusField.stringValue = "" case .updating: statusField.stringValue = "Updating…" case .updated(let date): var relativeDate = date if Int(relativeDate.timeIntervalSince1970) == Int(Date().timeIntervalSince1970) { // Avoid issues with relative time marking it as "in 0 sec." relativeDate = Date(timeIntervalSinceNow: -1) } let dateTimeFormatter = RelativeDateTimeFormatter() dateTimeFormatter.dateTimeStyle = .numeric dateTimeFormatter.unitsStyle = .short let dateString = dateTimeFormatter.string(for: relativeDate)! // Cannot be nil when date is Date statusField.stringValue = "Updated \(dateString)" } } @objc private func reloadServices() { reloadServicesCallback() } @objc private func openSettings() { openSettingsCallback() } } ================================================ FILE: stts/CustomScrollView.swift ================================================ // // CustomScrollView.swift // stts // import Cocoa class CustomScrollView: NSScrollView { var topConstraint: NSLayoutConstraint? override var isOpaque: Bool { return false } } ================================================ FILE: stts/DataLoader.swift ================================================ // // Loading.swift // stts // import Foundation import Kanna private var _sharedWithoutCaching: URLSession? extension URLSession { static var sharedWithoutCaching: URLSession { if let session = _sharedWithoutCaching { return session } else { let config = URLSessionConfiguration.default config.requestCachePolicy = .reloadIgnoringLocalCacheData config.urlCache = nil let session = URLSession(configuration: config) _sharedWithoutCaching = session return session } } } public protocol URLSessionProtocol { func data(for request: URLRequest) async throws -> (Data, URLResponse) func data(from url: URL) async throws -> (Data, URLResponse) } extension URLSession: URLSessionProtocol {} class DataLoader: URLSessionProtocol { #if DEBUG // For testing static var shared = DataLoader() #else static let shared = DataLoader() #endif private let session: URLSessionProtocol init(session: URLSessionProtocol = URLSession.sharedWithoutCaching) { self.session = session } func data(for request: URLRequest) async throws -> (Data, URLResponse) { try await session.data(for: request) } func data(from url: URL) async throws -> (Data, URLResponse) { try await session.data(from: url) } } protocol Loading { func data(for request: URLRequest) async throws -> (Data, URLResponse) func data(from url: URL) async throws -> (Data, URLResponse) } extension Loading { func data(for request: URLRequest) async throws -> (Data, URLResponse) { try await DataLoader.shared.data(for: request) } func data(from url: URL) async throws -> (Data, URLResponse) { try await DataLoader.shared.data(from: url) } func rawData(from url: URL) async throws -> Data { do { return try await self.data(from: url).0 } catch { throw StatusUpdateError.networkError(error) } } func rawString(from url: URL) async throws -> String { let data = try await rawData(from: url) if let rawContents = String(data: data, encoding: .utf8) { return rawContents } else { throw StatusUpdateError.parseError(nil) } } func html(from url: URL) async throws -> HTMLDocument { let data = try await rawData(from: url) do { return try HTML(html: data, encoding: .utf8) } catch { throw StatusUpdateError.parseError(error) } } func decoded(_ type: T.Type, from url: URL) async throws -> T { let data = try await rawData(from: url) do { return try JSONDecoder().decode(type, from: data) } catch { throw StatusUpdateError.decodingError(error) } } func rawData(for request: URLRequest) async throws -> Data { do { return try await self.data(for: request).0 } catch { throw StatusUpdateError.networkError(error) } } } ================================================ FILE: stts/EditorTableView/EditorTableCell.swift ================================================ // // EditorTableCell.swift // stts // import Cocoa import SFSafeSymbols final class EditorTableCell: NSTableCellView { enum Design { static let padding = NSEdgeInsets(top: 10, left: 0, bottom: 10, right: 0) static let innerSpacing: CGFloat = 4 enum Name { static let categoryFont = NSFont.systemFont(ofSize: 13, weight: .bold) static let font = NSFont.systemFont(ofSize: 13) } enum ToggleButton { static let size = NSSize(width: 36, height: 20) } enum ArrowImage { static let size = NSSize(width: 20, height: 20) } } enum CellType { case none case back case service case category } static let identifier: NSUserInterfaceItemIdentifier = .init(String(describing: EditorTableCell.self)) static let defaultHeight: CGFloat = 30 private let stackView = NSStackView() private let leadingImageView = NSImageView() private lazy var backButton = NSButton( image: NSImage(systemSymbol: .chevronLeft), target: self, action: #selector(EditorTableCell.back) ) private let toggleButton = NSButton() private let trailingImageView = NSImageView() var selected: Bool = false { didSet { setNeedsDisplay(frame) } } var toggleCallback: () -> Void = {} var backCallback: () -> Void = {} var type: CellType = .none { didSet { switch type { case .none: leadingImageView.isHidden = true backButton.isHidden = true textField?.isHidden = true toggleButton.isHidden = true trailingImageView.isHidden = true case .back: leadingImageView.isHidden = false backButton.isHidden = false textField?.isHidden = false toggleButton.isHidden = true trailingImageView.isHidden = true textField?.font = Design.Name.categoryFont case .service: leadingImageView.isHidden = true backButton.isHidden = true textField?.isHidden = false toggleButton.isHidden = false trailingImageView.isHidden = true textField?.font = Design.Name.font case .category: leadingImageView.isHidden = true backButton.isHidden = true textField?.isHidden = false toggleButton.isHidden = true trailingImageView.isHidden = false textField?.font = Design.Name.font } } } static func estimatedHeight(for serviceDefinition: ServiceDefinition, maxWidth: CGFloat) -> CGFloat { serviceDefinition.name.height( forWidth: maxWidth, font: Design.Name.font ) + Design.padding.top + Design.padding.bottom } static func maxNameWidth(for tableView: NSTableView) -> CGFloat { tableView.frame.size.width - Design.innerSpacing - Design.ToggleButton.size.width } override init(frame frameRect: NSRect) { super.init(frame: frameRect) commonInit() } required init?(coder: NSCoder) { super.init(coder: coder) commonInit() } private func commonInit() { stackView.translatesAutoresizingMaskIntoConstraints = false stackView.orientation = .horizontal addSubview(stackView) backButton.symbolConfiguration = NSImage.SymbolConfiguration(scale: .medium) backButton.controlSize = .large backButton.bezelStyle = .texturedRounded let textField = NSTextField() textField.isEditable = false textField.isBordered = false textField.isSelectable = false self.textField = textField textField.font = Design.Name.font textField.textColor = NSColor.textColor textField.backgroundColor = NSColor.clear toggleButton.title = "" toggleButton.isBordered = false toggleButton.bezelStyle = .texturedSquare toggleButton.controlSize = .small toggleButton.target = self toggleButton.action = #selector(EditorTableCell.toggle) toggleButton.wantsLayer = true toggleButton.layer?.borderWidth = 1.5 toggleButton.layer?.cornerRadius = 5 leadingImageView.image = NSImage(systemSymbol: .chevronLeft) leadingImageView.symbolConfiguration = .init(pointSize: 14, weight: .medium) leadingImageView.contentTintColor = NSColor.tertiaryLabelColor trailingImageView.image = NSImage(systemSymbol: .chevronRight) trailingImageView.symbolConfiguration = .init(pointSize: 14, weight: .medium) trailingImageView.contentTintColor = NSColor.tertiaryLabelColor let spacer = NSView() spacer.setContentHuggingPriority(.defaultLow, for: .horizontal) for subview in [backButton, textField, spacer, toggleButton, trailingImageView] { stackView.addArrangedSubview(subview) } NSLayoutConstraint.activate([ stackView.centerYAnchor.constraint(equalTo: centerYAnchor, constant: -1), stackView.heightAnchor.constraint(equalTo: heightAnchor), stackView.leadingAnchor.constraint(equalTo: leadingAnchor), stackView.trailingAnchor.constraint(equalTo: trailingAnchor), backButton.widthAnchor.constraint(equalTo: backButton.heightAnchor), toggleButton.widthAnchor.constraint(equalToConstant: Design.ToggleButton.size.width), toggleButton.heightAnchor.constraint(equalToConstant: Design.ToggleButton.size.height), leadingImageView.widthAnchor.constraint(equalToConstant: Design.ArrowImage.size.width), leadingImageView.heightAnchor.constraint(equalToConstant: Design.ArrowImage.size.height), trailingImageView.widthAnchor.constraint(equalToConstant: Design.ArrowImage.size.width), trailingImageView.heightAnchor.constraint(equalToConstant: Design.ArrowImage.size.height) ]) } @objc func toggle() { self.selected = !selected toggleCallback() } @objc func back() { backCallback() } override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) let color = selected ? StatusColor.green : NSColor.tertiaryLabelColor let title = selected ? "ON" : "OFF" let backgroundColor = selected ? color.withAlphaComponent(0.1) : NSColor.clear toggleButton.title = title toggleButton.font = NSFont.monospacedSystemFont(ofSize: 12, weight: .medium) toggleButton.contentTintColor = color toggleButton.layer?.borderColor = color.cgColor toggleButton.layer?.backgroundColor = backgroundColor.cgColor } } ================================================ FILE: stts/Extensions/Atomic.swift ================================================ // // Atomic.swift // stts // import Foundation import os.lock private final class UnfairLock { private var _lock: UnsafeMutablePointer init() { _lock = UnsafeMutablePointer.allocate(capacity: 1) _lock.initialize(to: os_unfair_lock()) } deinit { _lock.deallocate() } func locked(_ f: () throws -> ReturnValue) rethrows -> ReturnValue { os_unfair_lock_lock(_lock) defer { os_unfair_lock_unlock(_lock) } return try f() } } @propertyWrapper public struct Atomic { private let lock = UnfairLock() private var value: Value public init(wrappedValue initialValue: Value) { value = initialValue } public var wrappedValue: Value { get { return lock.locked { value } } set(newValue) { lock.locked { value = newValue } } } } ================================================ FILE: stts/Extensions/NSScreenExtensions.swift ================================================ // // NSScreenExtensions.swift // stts // import Cocoa extension NSScreen { static var usableHeightOfActiveScreen: CGFloat? { // Active screen is the screen that has the mouse cursor let mouseLocation = NSEvent.mouseLocation let currentScreen = NSScreen.screens.first { // Big gotcha here, CGRect.contains(point) returns false when x or y is at maxX/maxY. // For a menu bar button, it's common for the user to click at the upper edge of the screen, for which // CGRect.contains(mouseLocation) would be false. Test this using our own method instead. ($0.frame.minX...$0.frame.maxX).contains(mouseLocation.x) && ($0.frame.minY...$0.frame.maxY).contains(mouseLocation.y) } if let currentScreen { let statusBarHeight = NSStatusBar.system.thickness return currentScreen.visibleFrame.height - statusBarHeight } else { return nil } } } ================================================ FILE: stts/Extensions/StringExtensions.swift ================================================ // // StringExtensions.swift // stts // import Cocoa extension String { var innerJSONString: String { let callbackPrefix = "jsonCallback(" let callbackSuffix = ");" let trimmedString = trimmingCharacters(in: .whitespacesAndNewlines) guard trimmedString.hasPrefix(callbackPrefix) && trimmedString.hasSuffix(callbackSuffix) else { return self } return String(trimmedString[ trimmedString.index(trimmedString.startIndex, offsetBy: callbackPrefix.count) ..< trimmedString.index(trimmedString.endIndex, offsetBy: -callbackSuffix.count) ]) } func height(forWidth width: CGFloat, font: NSFont) -> CGFloat { guard count > 0 else { return 0 } let attributedString = NSAttributedString( string: self, attributes: [.font: font] ) let size = NSSize(width: width, height: .infinity) let textContainer = NSTextContainer(containerSize: size) let textStorage = NSTextStorage(attributedString: attributedString) let layoutManager = NSLayoutManager() layoutManager.addTextContainer(textContainer) textStorage.addLayoutManager(layoutManager) layoutManager.hyphenationFactor = 0 layoutManager.typesetterBehavior = .latestBehavior // NSLayoutManager is lazy, so force it to calculate with this _ = layoutManager.glyphRange(for: textContainer) var result = layoutManager.usedRect(for: textContainer).size.height let extraLineSize = layoutManager.extraLineFragmentRect.size if extraLineSize.height > 0 { result -= extraLineSize.height } return result } var unescaped: String { var result = self // Convert escape sequences to the actual characters let entities = ["\0", "\t", "\n", "\r", "\"", "\'", "\\"] for entity in entities { let descriptionCharacters = entity.debugDescription.dropFirst().dropLast() let description = String(descriptionCharacters) result = result.replacingOccurrences(of: description, with: entity) } let invalidEscapedCharacters: [String: String] = ["\\\n": "\\n"] for (character, replacement) in invalidEscapedCharacters { result = result.replacingOccurrences(of: character, with: replacement) } // Convert unicode code points to characters: \u003e becomes > // swiftlint:disable:next force_try let regularExpression = try! NSRegularExpression(pattern: "\\\\u([A-Za-z0-9]{4})") var offset = 0 regularExpression.enumerateMatches( in: result, range: NSRange(location: 0, length: (result as NSString).length), using: { textCheckingResult, _, _ in guard let textCheckingResult, textCheckingResult.numberOfRanges > 1 else { return } let actualRange = NSRange( location: textCheckingResult.range.location + offset, length: textCheckingResult.range.length ) let codePointRange = NSRange( location: textCheckingResult.range(at: 1).location + offset, length: textCheckingResult.range(at: 1).length ) let codePoint = (result as NSString).substring(with: codePointRange) guard let codePointInt = UInt32(codePoint, radix: 16), let scalar = Unicode.Scalar(codePointInt) else { return } let replacement = String(scalar) result = (result as NSString).replacingCharacters( in: actualRange, with: replacement ) offset += (replacement.count - textCheckingResult.range.length) } ) return result } } ================================================ FILE: stts/Extensions/TaskExtensions.swift ================================================ // // Task.swift // stts // import Foundation public extension Task where Success == Never, Failure == Never { static func sleep(seconds: TimeInterval) async throws { let duration = UInt64(seconds * 1_000_000_000) try await Task.sleep(nanoseconds: duration) } } ================================================ FILE: stts/HeadlessHTMLRenderer.swift ================================================ // // HeadlessHTMLRenderer.swift // stts // import Cocoa import WebKit // Because some services obfuscate the javascript a LOT (whyyyyyy? why do you even need javascript for a status page? // this why I quit web development, y'all keep making stuff up just to keep yourself relevant) and we have better things // to do than decrypt that, this is a wrapper that creates a web view to render the page and run its javascript // only to read the DOM then discard the web view immediately. The Web Content process that gets spawned likely uses // more memory than the entire stts app and should not be allowed to stay alive. // This is a last resort and shouldn't be used unless necessary otherwise we would be creating too many web views (and/ // or have to make some sort of limiter to deal with that...) @MainActor class HeadlessHTMLRenderer: NSObject, WKNavigationDelegate { private var webView: WKWebView? private var continuation: CheckedContinuation? func retrieveRenderedHTML(for url: URL) async -> String? { await withCheckedContinuation { continuation in // Resume and discard any in-flight request self.continuation?.resume(returning: nil) self.continuation = continuation let webView = WKWebView() webView.navigationDelegate = self webView.load(URLRequest(url: url)) self.webView = webView } } func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { guard webView == self.webView, let continuation else { return } self.continuation = nil Task { let html = try? await webView.evaluateJavaScript("document.body.innerHTML") continuation.resume(returning: html as? String) // Discard the web view so that the web content process is killed if webView == self.webView { self.webView = nil } } } func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: any Error) { guard webView == self.webView, let continuation else { return } self.continuation = nil self.webView = nil continuation.resume(returning: nil) } func webView( _ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: any Error ) { guard webView == self.webView, let continuation else { return } self.continuation = nil self.webView = nil continuation.resume(returning: nil) } } ================================================ FILE: stts/Icons.swift ================================================ // // Icons.swift // stts // import Cocoa class CheckmarkIcon: NSView { var color: NSColor = NSColor(calibratedRed: 0.46, green: 0.78, blue: 0.56, alpha: 1) { didSet { self.needsDisplay = true } } override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) color.setStroke() let checkmarkPath = NSBezierPath() checkmarkPath.lineWidth = 3 checkmarkPath.move(to: NSPoint(x: 17.01, y: 9.15)) checkmarkPath.curve(to: NSPoint(x: 16.3, y: 9.45), controlPoint1: NSPoint(x: 16.75, y: 9.15), controlPoint2: NSPoint(x: 16.5, y: 9.25)) checkmarkPath.line(to: NSPoint(x: 2.3, y: 23.45)) checkmarkPath.line(to: NSPoint(x: 3.71, y: 24.86)) checkmarkPath.line(to: NSPoint(x: 17.01, y: 11.57)) checkmarkPath.line(to: NSPoint(x: 42.3, y: 36.86)) checkmarkPath.line(to: NSPoint(x: 43.71, y: 35.45)) checkmarkPath.line(to: NSPoint(x: 17.71, y: 9.45)) checkmarkPath.curve(to: NSPoint(x: 17.01, y: 9.15), controlPoint1: NSPoint(x: 17.52, y: 9.25), controlPoint2: NSPoint(x: 17.26, y: 9.15)) checkmarkPath.close() checkmarkPath.stroke() } } class CrossIcon: NSView { var color: NSColor = NSColor(calibratedRed: 0.9, green: 0.78, blue: 0.56, alpha: 1) { didSet { self.needsDisplay = true } } override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) color.setFill() let context = NSGraphicsContext.current!.cgContext NSGraphicsContext.saveGraphicsState() context.translateBy(x: 23, y: 23) context.rotate(by: -45 * CGFloat.pi / 180) NSBezierPath(rect: NSRect(x: -26.88, y: -1, width: 53.75, height: 4)).fill() NSGraphicsContext.restoreGraphicsState() NSGraphicsContext.saveGraphicsState() context.translateBy(x: 23, y: 23) context.rotate(by: -45 * CGFloat.pi / 180) NSBezierPath(rect: NSRect(x: -1, y: -26.88, width: 4, height: 53.75)).fill() NSGraphicsContext.restoreGraphicsState() } } class RefreshIcon: NSView { var color = NSColor.secondaryLabelColor { didSet { self.needsDisplay = true } } override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) color.setFill() let circle = NSBezierPath() circle.move(to: NSPoint(x: 23, y: 3)) circle.line(to: NSPoint(x: 23, y: 5)) circle.curve(to: NSPoint(x: 41, y: 23), controlPoint1: NSPoint(x: 32.93, y: 5), controlPoint2: NSPoint(x: 41, y: 13.07)) circle.curve(to: NSPoint(x: 23, y: 41), controlPoint1: NSPoint(x: 41, y: 32.93), controlPoint2: NSPoint(x: 32.93, y: 41)) circle.curve(to: NSPoint(x: 5, y: 23), controlPoint1: NSPoint(x: 13.07, y: 41), controlPoint2: NSPoint(x: 5, y: 32.93)) circle.curve(to: NSPoint(x: 14.47, y: 7.14), controlPoint1: NSPoint(x: 5, y: 16.37), controlPoint2: NSPoint(x: 8.63, y: 10.29)) circle.line(to: NSPoint(x: 13.53, y: 5.38)) circle.curve(to: NSPoint(x: 3, y: 23), controlPoint1: NSPoint(x: 7.03, y: 8.88), controlPoint2: NSPoint(x: 3, y: 15.63)) circle.curve(to: NSPoint(x: 23, y: 43), controlPoint1: NSPoint(x: 3, y: 34.03), controlPoint2: NSPoint(x: 11.97, y: 43)) circle.curve(to: NSPoint(x: 43, y: 23), controlPoint1: NSPoint(x: 34.03, y: 43), controlPoint2: NSPoint(x: 43, y: 34.03)) circle.curve(to: NSPoint(x: 23, y: 3), controlPoint1: NSPoint(x: 43, y: 11.97), controlPoint2: NSPoint(x: 34.03, y: 3)) circle.close() circle.fill() let arrowHead = NSBezierPath() arrowHead.move(to: NSPoint(x: 4.2, y: 3.02)) arrowHead.line(to: NSPoint(x: 3.8, y: 4.98)) arrowHead.line(to: NSPoint(x: 13, y: 6.82)) arrowHead.line(to: NSPoint(x: 13, y: 16)) arrowHead.line(to: NSPoint(x: 15, y: 16)) arrowHead.line(to: NSPoint(x: 15, y: 6)) arrowHead.curve(to: NSPoint(x: 14.2, y: 5.02), controlPoint1: NSPoint(x: 15, y: 5.52), controlPoint2: NSPoint(x: 14.66, y: 5.11)) arrowHead.line(to: NSPoint(x: 4.2, y: 3.02)) arrowHead.close() arrowHead.fill() } } class GearIcon: NSView { var color = NSColor.secondaryLabelColor { didSet { self.needsDisplay = true } } override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) color.setFill() let outerCog = NSBezierPath() outerCog.move(to: NSPoint(x: 26.76, y: 9.49)) outerCog.curve(to: NSPoint(x: 27.62, y: 8.99), controlPoint1: NSPoint(x: 27.11, y: 9.49), controlPoint2: NSPoint(x: 27.44, y: 9.3)) outerCog.line(to: NSPoint(x: 28.4, y: 7.64)) outerCog.curve(to: NSPoint(x: 31.13, y: 6.9), controlPoint1: NSPoint(x: 28.93, y: 6.72), controlPoint2: NSPoint(x: 30.21, y: 6.37)) outerCog.line(to: NSPoint(x: 32.87, y: 7.9)) outerCog.curve(to: NSPoint(x: 33.6, y: 10.64), controlPoint1: NSPoint(x: 33.82, y: 8.46), controlPoint2: NSPoint(x: 34.15, y: 9.68)) outerCog.line(to: NSPoint(x: 32.82, y: 11.98)) outerCog.curve(to: NSPoint(x: 32.98, y: 13.18), controlPoint1: NSPoint(x: 32.6, y: 12.37), controlPoint2: NSPoint(x: 32.66, y: 12.86)) outerCog.curve(to: NSPoint(x: 36.48, y: 19.26), controlPoint1: NSPoint(x: 34.63, y: 14.87), controlPoint2: NSPoint(x: 35.85, y: 16.97)) outerCog.curve(to: NSPoint(x: 37.44, y: 19.99), controlPoint1: NSPoint(x: 36.6, y: 19.69), controlPoint2: NSPoint(x: 36.99, y: 19.99)) outerCog.line(to: NSPoint(x: 39, y: 19.99)) outerCog.curve(to: NSPoint(x: 41, y: 21.99), controlPoint1: NSPoint(x: 40.1, y: 19.99), controlPoint2: NSPoint(x: 41, y: 20.89)) outerCog.line(to: NSPoint(x: 41, y: 23.99)) outerCog.curve(to: NSPoint(x: 39, y: 25.99), controlPoint1: NSPoint(x: 41, y: 25.1), controlPoint2: NSPoint(x: 40.1, y: 25.99)) outerCog.line(to: NSPoint(x: 37.44, y: 25.99)) outerCog.curve(to: NSPoint(x: 36.48, y: 26.73), controlPoint1: NSPoint(x: 36.99, y: 25.99), controlPoint2: NSPoint(x: 36.6, y: 26.29)) outerCog.curve(to: NSPoint(x: 32.98, y: 32.81), controlPoint1: NSPoint(x: 35.85, y: 29.02), controlPoint2: NSPoint(x: 34.63, y: 31.12)) outerCog.curve(to: NSPoint(x: 32.82, y: 34.01), controlPoint1: NSPoint(x: 32.66, y: 33.13), controlPoint2: NSPoint(x: 32.6, y: 33.62)) outerCog.line(to: NSPoint(x: 33.6, y: 35.35)) outerCog.curve(to: NSPoint(x: 32.87, y: 38.08), controlPoint1: NSPoint(x: 34.15, y: 36.3), controlPoint2: NSPoint(x: 33.82, y: 37.53)) outerCog.line(to: NSPoint(x: 31.13, y: 39.08)) outerCog.curve(to: NSPoint(x: 28.4, y: 38.35), controlPoint1: NSPoint(x: 30.21, y: 39.62), controlPoint2: NSPoint(x: 28.93, y: 39.26)) outerCog.line(to: NSPoint(x: 27.62, y: 37)) outerCog.curve(to: NSPoint(x: 26.51, y: 36.53), controlPoint1: NSPoint(x: 27.4, y: 36.61), controlPoint2: NSPoint(x: 26.94, y: 36.42)) outerCog.curve(to: NSPoint(x: 19.49, y: 36.53), controlPoint1: NSPoint(x: 24.14, y: 37.14), controlPoint2: NSPoint(x: 21.86, y: 37.14)) outerCog.curve(to: NSPoint(x: 18.38, y: 37), controlPoint1: NSPoint(x: 19.06, y: 36.42), controlPoint2: NSPoint(x: 18.6, y: 36.61)) outerCog.line(to: NSPoint(x: 17.6, y: 38.35)) outerCog.curve(to: NSPoint(x: 14.87, y: 39.08), controlPoint1: NSPoint(x: 17.07, y: 39.26), controlPoint2: NSPoint(x: 15.79, y: 39.62)) outerCog.line(to: NSPoint(x: 13.13, y: 38.08)) outerCog.curve(to: NSPoint(x: 12.4, y: 35.35), controlPoint1: NSPoint(x: 12.18, y: 37.53), controlPoint2: NSPoint(x: 11.85, y: 36.3)) outerCog.line(to: NSPoint(x: 13.18, y: 34.01)) outerCog.curve(to: NSPoint(x: 13.02, y: 32.81), controlPoint1: NSPoint(x: 13.4, y: 33.62), controlPoint2: NSPoint(x: 13.34, y: 33.13)) outerCog.curve(to: NSPoint(x: 9.52, y: 26.73), controlPoint1: NSPoint(x: 11.36, y: 31.12), controlPoint2: NSPoint(x: 10.15, y: 29.02)) outerCog.curve(to: NSPoint(x: 8.56, y: 25.99), controlPoint1: NSPoint(x: 9.4, y: 26.29), controlPoint2: NSPoint(x: 9.01, y: 25.99)) outerCog.line(to: NSPoint(x: 7, y: 25.99)) outerCog.curve(to: NSPoint(x: 5, y: 23.99), controlPoint1: NSPoint(x: 5.9, y: 25.99), controlPoint2: NSPoint(x: 5, y: 25.1)) outerCog.line(to: NSPoint(x: 5, y: 21.99)) outerCog.curve(to: NSPoint(x: 7, y: 19.99), controlPoint1: NSPoint(x: 5, y: 20.89), controlPoint2: NSPoint(x: 5.9, y: 19.99)) outerCog.line(to: NSPoint(x: 8.56, y: 19.99)) outerCog.curve(to: NSPoint(x: 9.52, y: 19.26), controlPoint1: NSPoint(x: 9.01, y: 19.99), controlPoint2: NSPoint(x: 9.4, y: 19.69)) outerCog.curve(to: NSPoint(x: 13.02, y: 13.18), controlPoint1: NSPoint(x: 10.15, y: 16.97), controlPoint2: NSPoint(x: 11.36, y: 14.87)) outerCog.curve(to: NSPoint(x: 13.18, y: 11.98), controlPoint1: NSPoint(x: 13.34, y: 12.86), controlPoint2: NSPoint(x: 13.4, y: 12.37)) outerCog.line(to: NSPoint(x: 12.4, y: 10.64)) outerCog.curve(to: NSPoint(x: 13.13, y: 7.9), controlPoint1: NSPoint(x: 11.85, y: 9.68), controlPoint2: NSPoint(x: 12.18, y: 8.46)) outerCog.line(to: NSPoint(x: 14.87, y: 6.9)) outerCog.curve(to: NSPoint(x: 17.6, y: 7.64), controlPoint1: NSPoint(x: 15.79, y: 6.37), controlPoint2: NSPoint(x: 17.07, y: 6.73)) outerCog.line(to: NSPoint(x: 18.38, y: 8.99)) outerCog.curve(to: NSPoint(x: 19.49, y: 9.46), controlPoint1: NSPoint(x: 18.6, y: 9.38), controlPoint2: NSPoint(x: 19.06, y: 9.57)) outerCog.curve(to: NSPoint(x: 26.51, y: 9.45), controlPoint1: NSPoint(x: 21.86, y: 8.84), controlPoint2: NSPoint(x: 24.14, y: 8.84)) outerCog.curve(to: NSPoint(x: 26.76, y: 9.49), controlPoint1: NSPoint(x: 26.59, y: 9.48), controlPoint2: NSPoint(x: 26.67, y: 9.49)) outerCog.close() outerCog.move(to: NSPoint(x: 30.14, y: 4.64)) outerCog.curve(to: NSPoint(x: 26.67, y: 6.64), controlPoint1: NSPoint(x: 28.71, y: 4.64), controlPoint2: NSPoint(x: 27.38, y: 5.4)) outerCog.line(to: NSPoint(x: 26.26, y: 7.34)) outerCog.curve(to: NSPoint(x: 19.74, y: 7.34), controlPoint1: NSPoint(x: 24.06, y: 6.88), controlPoint2: NSPoint(x: 21.94, y: 6.88)) outerCog.line(to: NSPoint(x: 19.33, y: 6.64)) outerCog.curve(to: NSPoint(x: 15.86, y: 4.64), controlPoint1: NSPoint(x: 18.62, y: 5.4), controlPoint2: NSPoint(x: 17.29, y: 4.64)) outerCog.curve(to: NSPoint(x: 13.87, y: 5.17), controlPoint1: NSPoint(x: 15.16, y: 4.64), controlPoint2: NSPoint(x: 14.47, y: 4.82)) outerCog.line(to: NSPoint(x: 12.13, y: 6.17)) outerCog.curve(to: NSPoint(x: 10.67, y: 11.64), controlPoint1: NSPoint(x: 10.22, y: 7.28), controlPoint2: NSPoint(x: 9.57, y: 9.73)) outerCog.line(to: NSPoint(x: 11.07, y: 12.34)) outerCog.curve(to: NSPoint(x: 7.81, y: 17.99), controlPoint1: NSPoint(x: 9.61, y: 13.97), controlPoint2: NSPoint(x: 8.5, y: 15.9)) outerCog.line(to: NSPoint(x: 7, y: 17.99)) outerCog.curve(to: NSPoint(x: 3, y: 21.99), controlPoint1: NSPoint(x: 4.79, y: 17.99), controlPoint2: NSPoint(x: 3, y: 19.79)) outerCog.line(to: NSPoint(x: 3, y: 23.99)) outerCog.curve(to: NSPoint(x: 7, y: 27.99), controlPoint1: NSPoint(x: 3, y: 26.2), controlPoint2: NSPoint(x: 4.79, y: 27.99)) outerCog.line(to: NSPoint(x: 7.81, y: 27.99)) outerCog.curve(to: NSPoint(x: 11.07, y: 33.65), controlPoint1: NSPoint(x: 8.5, y: 30.08), controlPoint2: NSPoint(x: 9.61, y: 32.02)) outerCog.line(to: NSPoint(x: 10.67, y: 34.35)) outerCog.curve(to: NSPoint(x: 12.13, y: 39.81), controlPoint1: NSPoint(x: 9.57, y: 36.26), controlPoint2: NSPoint(x: 10.22, y: 38.71)) outerCog.line(to: NSPoint(x: 13.87, y: 40.81)) outerCog.curve(to: NSPoint(x: 15.86, y: 41.35), controlPoint1: NSPoint(x: 14.47, y: 41.16), controlPoint2: NSPoint(x: 15.16, y: 41.35)) outerCog.curve(to: NSPoint(x: 19.33, y: 39.35), controlPoint1: NSPoint(x: 17.29, y: 41.35), controlPoint2: NSPoint(x: 18.62, y: 40.58)) outerCog.line(to: NSPoint(x: 19.74, y: 38.64)) outerCog.curve(to: NSPoint(x: 26.26, y: 38.64), controlPoint1: NSPoint(x: 21.94, y: 39.11), controlPoint2: NSPoint(x: 24.06, y: 39.11)) outerCog.line(to: NSPoint(x: 26.67, y: 39.35)) outerCog.curve(to: NSPoint(x: 30.14, y: 41.35), controlPoint1: NSPoint(x: 27.38, y: 40.58), controlPoint2: NSPoint(x: 28.71, y: 41.35)) outerCog.curve(to: NSPoint(x: 32.13, y: 40.81), controlPoint1: NSPoint(x: 30.84, y: 41.35), controlPoint2: NSPoint(x: 31.53, y: 41.16)) outerCog.line(to: NSPoint(x: 33.87, y: 39.81)) outerCog.curve(to: NSPoint(x: 35.33, y: 34.35), controlPoint1: NSPoint(x: 35.78, y: 38.71), controlPoint2: NSPoint(x: 36.43, y: 36.26)) outerCog.line(to: NSPoint(x: 34.93, y: 33.65)) outerCog.curve(to: NSPoint(x: 38.19, y: 27.99), controlPoint1: NSPoint(x: 36.39, y: 32.02), controlPoint2: NSPoint(x: 37.5, y: 30.08)) outerCog.line(to: NSPoint(x: 39, y: 27.99)) outerCog.curve(to: NSPoint(x: 43, y: 23.99), controlPoint1: NSPoint(x: 41.21, y: 27.99), controlPoint2: NSPoint(x: 43, y: 26.2)) outerCog.line(to: NSPoint(x: 43, y: 21.99)) outerCog.curve(to: NSPoint(x: 39, y: 17.99), controlPoint1: NSPoint(x: 43, y: 19.79), controlPoint2: NSPoint(x: 41.21, y: 17.99)) outerCog.line(to: NSPoint(x: 38.19, y: 17.99)) outerCog.curve(to: NSPoint(x: 34.93, y: 12.34), controlPoint1: NSPoint(x: 37.5, y: 15.9), controlPoint2: NSPoint(x: 36.39, y: 13.97)) outerCog.line(to: NSPoint(x: 35.33, y: 11.64)) outerCog.curve(to: NSPoint(x: 33.87, y: 6.17), controlPoint1: NSPoint(x: 36.43, y: 9.73), controlPoint2: NSPoint(x: 35.78, y: 7.28)) outerCog.line(to: NSPoint(x: 32.13, y: 5.17)) outerCog.curve(to: NSPoint(x: 30.14, y: 4.64), controlPoint1: NSPoint(x: 31.53, y: 4.82), controlPoint2: NSPoint(x: 30.84, y: 4.64)) outerCog.close() outerCog.fill() let innerCircle = NSBezierPath() innerCircle.move(to: NSPoint(x: 23, y: 29.99)) innerCircle.curve(to: NSPoint(x: 16, y: 22.99), controlPoint1: NSPoint(x: 19.14, y: 29.99), controlPoint2: NSPoint(x: 16, y: 26.85)) innerCircle.curve(to: NSPoint(x: 23, y: 15.99), controlPoint1: NSPoint(x: 16, y: 19.13), controlPoint2: NSPoint(x: 19.14, y: 15.99)) innerCircle.curve(to: NSPoint(x: 30, y: 22.99), controlPoint1: NSPoint(x: 26.86, y: 15.99), controlPoint2: NSPoint(x: 30, y: 19.13)) innerCircle.curve(to: NSPoint(x: 23, y: 29.99), controlPoint1: NSPoint(x: 30, y: 26.85), controlPoint2: NSPoint(x: 26.86, y: 29.99)) innerCircle.close() innerCircle.move(to: NSPoint(x: 23, y: 13.99)) innerCircle.curve(to: NSPoint(x: 14, y: 22.99), controlPoint1: NSPoint(x: 18.04, y: 13.99), controlPoint2: NSPoint(x: 14, y: 18.03)) innerCircle.curve(to: NSPoint(x: 23, y: 31.99), controlPoint1: NSPoint(x: 14, y: 27.96), controlPoint2: NSPoint(x: 18.04, y: 31.99)) innerCircle.curve(to: NSPoint(x: 32, y: 22.99), controlPoint1: NSPoint(x: 27.96, y: 31.99), controlPoint2: NSPoint(x: 32, y: 27.96)) innerCircle.curve(to: NSPoint(x: 23, y: 13.99), controlPoint1: NSPoint(x: 32, y: 18.03), controlPoint2: NSPoint(x: 27.96, y: 13.99)) innerCircle.close() innerCircle.fill() } } ================================================ FILE: stts/Preferences/PreferencesGeneralView.swift ================================================ // // PreferencesGeneralView.swift // stts // import Cocoa import PreferencesWindow class PreferencesGeneralView: VenturaPreferencesView { private let quitButton = NSButton(title: "Quit stts", target: NSApp, action: #selector(NSApplication.terminate(_:))) init() { super.init( items: [ .init(title: "First section"): [ .init(title: "Start at login", actions: [.switch(initialValue: true, changeCallback: { _ in })]), .init( title: "Notify when a status changes", actions: [.switch(initialValue: true, changeCallback: { _ in })] ), .init( title: "Hide details of available services", actions: [.switch(initialValue: false, changeCallback: { _ in })] ) ] ] ) quitButton.bezelStyle = .rounded quitButton.translatesAutoresizingMaskIntoConstraints = false addSubview(quitButton) NSLayoutConstraint.activate([ heightAnchor.constraint(equalToConstant: 400), widthAnchor.constraint(equalToConstant: 400), quitButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16), quitButton.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -20) ]) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } class VenturaPreferencesView: NSView, PreferencesView { struct Section: Hashable { let id = UUID() let title: String? } struct Item: Hashable { let id = UUID() let title: String let actions: [Action] static func == (lhs: VenturaPreferencesView.Item, rhs: VenturaPreferencesView.Item) -> Bool { lhs.id == rhs.id } func hash(into hasher: inout Hasher) { hasher.combine(id) } } enum Action { case `switch`(initialValue: Bool, changeCallback: (_ newValue: Bool) -> Void) } final class Cell: NSTableCellView { static let identifier: NSUserInterfaceItemIdentifier = .init(String(describing: Cell.self)) private let stackView = NSStackView() private let switchButton = NSSwitch() var text: String = "" { didSet { textField?.stringValue = text } } var actions: [Action] = [] { didSet { for control in [switchButton] { control.isHidden = true } for action in actions { switch action { case let .switch(initialValue: initialValue, changeCallback: _): switchButton.isHidden = false switchButton.state = initialValue ? .on : .off } } } } init() { super.init(frame: .zero) commonInit() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func commonInit() { stackView.translatesAutoresizingMaskIntoConstraints = false stackView.orientation = .horizontal addSubview(stackView) let textField = NSTextField() textField.isEditable = false textField.isBordered = false textField.isSelectable = false self.textField = textField textField.font = NSFont.systemFont(ofSize: 13) textField.textColor = NSColor.textColor textField.backgroundColor = NSColor.clear let spacer = NSView() spacer.setContentHuggingPriority(.defaultLow, for: .horizontal) switchButton.target = self switchButton.action = #selector(changedSwitchValue) switchButton.controlSize = .mini for subview in [textField, spacer, switchButton] { stackView.addArrangedSubview(subview) } NSLayoutConstraint.activate([ stackView.centerYAnchor.constraint(equalTo: centerYAnchor), stackView.heightAnchor.constraint(equalTo: heightAnchor), stackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 2), stackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10) ]) } @objc private func changedSwitchValue() { let switchIsOn = switchButton.state == .on || switchButton.state == .mixed for action in actions { switch action { case let .switch(initialValue: _, changeCallback: callback): callback(switchIsOn) } } } } private let items: [Section: [Item]] private var flatItems: [Item] = [] private let box = NSBox() private let tableView = NSTableView() init(items: [Section: [Item]]) { self.items = items super.init(frame: .zero) commonInit() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func commonInit() { flatItems = items.values.flatMap { $0 } box.translatesAutoresizingMaskIntoConstraints = false box.titlePosition = .noTitle box.contentView = tableView box.contentViewMargins = NSSize(width: 0, height: 0) box.focusRingType = .none addSubview(box) let column = NSTableColumn(identifier: Cell.identifier) tableView.addTableColumn(column) tableView.autoresizesSubviews = true tableView.headerView = nil tableView.gridStyleMask = .solidHorizontalGridLineMask tableView.focusRingType = .none tableView.selectionHighlightStyle = .none tableView.dataSource = self tableView.delegate = self tableView.backgroundColor = NSColor.clear tableView.style = .fullWidth tableView.rowHeight = 36 tableView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ box.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 12), box.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 12), box.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -12), tableView.topAnchor.constraint(equalTo: box.topAnchor), tableView.leadingAnchor.constraint(equalTo: box.leadingAnchor), tableView.trailingAnchor.constraint(equalTo: box.trailingAnchor), tableView.bottomAnchor.constraint(equalTo: box.bottomAnchor) ]) } func willShow() {} } extension VenturaPreferencesView: NSTableViewDataSource { func numberOfRows(in tableView: NSTableView) -> Int { flatItems.count } } extension VenturaPreferencesView: NSTableViewDelegate { func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { let cell = tableView.makeView(withIdentifier: Cell.identifier, owner: self) as? Cell ?? Cell() cell.text = flatItems[row].title cell.actions = flatItems[row].actions return cell } func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? { let rowView = SettingsTableRowView() rowView.showSeparator = row != 0 return rowView } } private class SettingsTableRowView: NSTableRowView { var showSeparator = true override func drawSeparator(in dirtyRect: NSRect) { guard showSeparator else { return } NSColor.separatorColor.setFill() NSRect(x: 0, y: 0, width: bounds.width, height: 1).fill() } } ================================================ FILE: stts/Preferences/PreferencesServicesView.swift ================================================ // // PreferencesServicesView.swift // stts // import Cocoa import PreferencesWindow import Combine final class PreferencesServicesView: NSView { private enum Filter: Int, CaseIterable { case availableServices = 0 case enabledServices = 1 var title: String { switch self { case .availableServices: return "Available" case .enabledServices: return "Enabled" } } } private let box = NSBox() private let scrollView = NSScrollView() private let tableView = NSTableView() private let serviceLoader: ServiceLoader private let preferences: Preferences private var filteredServices: [ServiceDefinition] private var selectedServices: [ServiceDefinition] var saveCallback: (() -> Void)? private var selectionChanged = false private var savedScrollPosition: CGPoint = .zero private let saveButton: NSButton = { let button = NSButton(title: "Save", target: nil, action: nil) button.bezelStyle = .rounded button.isEnabled = false return button }() private let searchField = NSSearchField() private lazy var filterSegmentedControl: NSSegmentedControl = { NSSegmentedControl( labels: Filter.allCases.map { $0.title }, trackingMode: .selectOne, target: self, action: #selector(updatedFilter) ) }() var selectedCategory: ServiceDefinition? { didSet { // Save the scroll position between screens let scrollToPosition: CGPoint? if selectedCategory != nil && oldValue == nil { savedScrollPosition = CGPoint(x: 0, y: tableView.visibleRect.minY) scrollToPosition = .zero } else if selectedCategory == nil && oldValue != nil { scrollToPosition = savedScrollPosition } else { scrollToPosition = nil } guard let categoryDefinition = selectedCategory, let serviceCategory = categoryDefinition.build() as? ServiceCategory else { // Show the unfiltered services filterServices() if let scrollPosition = scrollToPosition { tableView.scroll(scrollPosition) } return } // Find the sub services var subServices = serviceLoader.allServices.filter { serviceDefinition in guard serviceDefinition.isSubService == true, let service = serviceDefinition.build() else { return false } let mirror = Mirror(reflecting: service) // TODO: Check ServiceDefinition type instead let hasExpectedClass = mirror.subjectType == serviceCategory.subServiceSuperclass || mirror.superclassMirror?.subjectType == serviceCategory.subServiceSuperclass // Exclude the category so that we can add it at the top let isTheCategory = service is ServiceCategory return hasExpectedClass && !isTheCategory }.sorted(by: ServiceDefinitionSortByName) // Add the category as the top item subServices.insert(categoryDefinition, at: 0) filteredServices = subServices tableView.reloadData() if let scrollPosition = scrollToPosition { tableView.scroll(scrollPosition) } } } var isSearching: Bool { searchField.stringValue.trimmingCharacters(in: .whitespacesAndNewlines) != "" } var isFiltering: Bool { switch Filter(rawValue: filterSegmentedControl.selectedSegment) { case .availableServices, .none: return false case .enabledServices: return true } } init( serviceLoader: ServiceLoader, preferences: Preferences ) { self.serviceLoader = serviceLoader self.preferences = preferences filteredServices = serviceLoader.allServicesWithoutSubServices selectedServices = preferences.selectedServices super.init(frame: .zero) translatesAutoresizingMaskIntoConstraints = false commonInit() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func commonInit() { saveButton.translatesAutoresizingMaskIntoConstraints = false saveButton.target = self saveButton.action = #selector(save) addSubview(saveButton) searchField.translatesAutoresizingMaskIntoConstraints = false searchField.sendsSearchStringImmediately = true searchField.sendsWholeSearchString = false searchField.action = #selector(updatedSearchString) searchField.target = self addSubview(searchField) filterSegmentedControl.translatesAutoresizingMaskIntoConstraints = false filterSegmentedControl.selectedSegment = 0 addSubview(filterSegmentedControl) box.translatesAutoresizingMaskIntoConstraints = false box.titlePosition = .noTitle box.contentView = scrollView box.contentViewMargins = NSSize(width: 0, height: 0) box.focusRingType = .none addSubview(box) scrollView.borderType = .noBorder scrollView.hasVerticalScroller = true scrollView.hasHorizontalScroller = false scrollView.autoresizesSubviews = true scrollView.documentView = tableView scrollView.drawsBackground = false scrollView.wantsLayer = true scrollView.layer?.cornerRadius = 6 scrollView.backgroundColor = .clear let column = NSTableColumn(identifier: EditorTableCell.identifier) column.width = 200 tableView.addTableColumn(column) tableView.autoresizesSubviews = true tableView.headerView = nil tableView.gridStyleMask = .solidHorizontalGridLineMask tableView.dataSource = self tableView.delegate = self tableView.backgroundColor = NSColor.clear tableView.style = .fullWidth tableView.rowHeight = 38 NSLayoutConstraint.activate([ heightAnchor.constraint(greaterThanOrEqualToConstant: 600), widthAnchor.constraint(equalToConstant: 400), searchField.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 6), searchField.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 12), searchField.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -12), searchField.heightAnchor.constraint(equalToConstant: 28), filterSegmentedControl.topAnchor.constraint(equalTo: searchField.bottomAnchor, constant: 8), filterSegmentedControl.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 12), filterSegmentedControl.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -12), box.topAnchor.constraint(equalTo: filterSegmentedControl.bottomAnchor, constant: 12), box.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 12), box.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -12), box.bottomAnchor.constraint(equalTo: saveButton.topAnchor, constant: -12), saveButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16), saveButton.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -16) ]) } func deselectCategory() { selectedCategory = nil } @objc private func save() { selectionChanged = false saveButton.isEnabled = false saveCallback?() } @objc private func updatedSearchString() { deselectCategory() filterServices() } @objc private func updatedFilter() { deselectCategory() filterServices() } private func filterServices() { let searchString = searchField.stringValue var source: [ServiceDefinition] switch Filter(rawValue: filterSegmentedControl.selectedSegment) { case .availableServices, .none: if isSearching { source = serviceLoader.allServices } else { source = serviceLoader.allServicesWithoutSubServices } case .enabledServices: source = serviceLoader.allServices.filter { selectedServices.contains(where: $0.eq) } } if isSearching { // Can't filter array with NSPredicate without making Service inherit KVO from NSObject, therefore // we create an array of service names that we can run the predicate on let allServiceNames = source.compactMap { $0.name } as NSArray let predicate = NSPredicate(format: "SELF LIKE[cd] %@", argumentArray: ["*\(searchString)*"]) guard let filteredServiceNames = allServiceNames.filtered(using: predicate) as? [String] else { return } let filteredServiceNamesSet = Set(filteredServiceNames) filteredServices = source.filter { filteredServiceNamesSet.contains($0.name) } } else { filteredServices = source } if selectedCategory != nil { selectedCategory = nil } tableView.reloadData() } } extension PreferencesServicesView: PreferencesView { func willShow() { selectedServices = preferences.selectedServices selectedCategory = nil saveButton.isEnabled = false } } extension PreferencesServicesView: NSTableViewDataSource { func numberOfRows(in tableView: NSTableView) -> Int { if selectedCategory == nil { return filteredServices.count } else { return filteredServices.count + 1 } } func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { return nil } } extension PreferencesServicesView: NSTableViewDelegate { // swiftlint:disable:next cyclomatic_complexity func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { let identifier = tableColumn?.identifier ?? EditorTableCell.identifier let cell = tableView.makeView(withIdentifier: identifier, owner: self) ?? EditorTableCell() guard let view = cell as? EditorTableCell else { return nil } let isBackRow = selectedCategory != nil && row == 0 let serviceRow = selectedCategory == nil ? row : max(row - 1, 0) let serviceDefinition = filteredServices[serviceRow] if isBackRow { view.type = .back } else if isSearching || isFiltering || selectedCategory != nil { view.type = .service } else { view.type = (serviceDefinition.isCategory == true) ? .category : .service } switch view.type { case .none: view.textField?.stringValue = "" view.selected = false view.toggleCallback = {} view.backCallback = {} case .back: if let selectedCategory { guard let categoryService = selectedCategory.build() as? ServiceCategory else { assertionFailure("Expected to build category service without issues") return nil } view.textField?.stringValue = categoryService.categoryName } else { view.textField?.stringValue = "" } view.selected = false view.toggleCallback = {} view.backCallback = { [weak self] in self?.deselectCategory() } case .service: view.textField?.stringValue = serviceDefinition.name view.selected = selectedServices.contains(where: serviceDefinition.eq) view.toggleCallback = { [weak self] in guard let self else { return } selectionChanged = true saveButton.isEnabled = true if view.selected { selectedServices.append(serviceDefinition) } else { if let index = selectedServices.firstIndex(where: serviceDefinition.eq) { selectedServices.remove(at: index) } } preferences.selectedServices = selectedServices } view.backCallback = {} case .category: guard let categoryService = serviceDefinition.build() as? ServiceCategory else { assertionFailure("Expected to build category service without issues") return nil } view.textField?.stringValue = categoryService.categoryName view.selected = false view.toggleCallback = {} view.backCallback = {} } if let rowView = tableView.rowView(atRow: row, makeIfNecessary: false) as? ServiceTableRowView { rowView.usesWindowBackground = view.type == .back rowView.selectionHighlightStyle = view.type == .category ? .regular : .none } return view } func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? { let cellIdentifier = NSUserInterfaceItemIdentifier(rawValue: "rowView") let cell = tableView.makeView(withIdentifier: cellIdentifier, owner: self) ?? ServiceTableRowView() guard let view = cell as? ServiceTableRowView else { return nil } view.showSeparator = false return view } func tableViewSelectionDidChange(_ notification: Notification) { guard tableView.selectedRow != -1 else { return } let realSelectedRow = selectedCategory == nil ? tableView.selectedRow : max(tableView.selectedRow - 1, 0) let selectedServiceDefinition = filteredServices[realSelectedRow] // We're only interested in selections of categories if selectedServiceDefinition.isCategory == true { // Change the selected category selectedCategory = selectedServiceDefinition } } } ================================================ FILE: stts/Preferences/PreferencesWindow.swift ================================================ // // PreferencesWindow.swift // stts // import Cocoa import PreferencesWindow import SFSafeSymbols final class PreferencesWindow { let controller: PreferencesWindowController private let servicesView: PreferencesServicesView var saveCallback: (() -> Void)? { get { servicesView.saveCallback } set { servicesView.saveCallback = newValue } } init(serviceLoader: ServiceLoader, preferences: Preferences) { servicesView = PreferencesServicesView(serviceLoader: serviceLoader, preferences: preferences) controller = PreferencesWindowController(menuItems: [ Self.generalMenuItem(), PreferencesWindow.servicesMenuItem(servicesView: servicesView), Self.aboutMenuItem() ]) } func show() { controller.show() } private static func generalMenuItem() -> PreferencesSidebarMenuItem { PreferencesSidebarMenuItem( title: "General", symbol: .gearshapeFill, view: PreferencesGeneralView() ) } private static func servicesMenuItem(servicesView: PreferencesServicesView) -> PreferencesSidebarMenuItem { PreferencesSidebarMenuItem( title: "Services", symbol: .boltCircleFill, view: servicesView ) } private static func aboutMenuItem() -> PreferencesSidebarMenuItem { let content = AboutContent( links: [ AboutContent.Link( title: "GitHub", url: URL(string: "https://github.com/inket/stts")! ), AboutContent.Link( title: "Contributors", url: URL(string: "https://github.com/inket/stts/graphs/contributors")! ) ], credit: "Activity glyph (app icon) by Gregor Črešnar from the Noun Project" ) return PreferencesSidebarMenuItem( title: "About", symbol: .infoCircleFill, view: PreferencesAboutView(content: content) ) } } ================================================ FILE: stts/Preferences.swift ================================================ // // Preferences.swift // stts // import Foundation class Preferences { private let serviceLoader: ServiceLoader var notifyOnStatusChange: Bool { get { UserDefaults.standard.bool(forKey: "notifyOnStatusChange") } set { UserDefaults.standard.set(newValue, forKey: "notifyOnStatusChange") } } var hideServiceDetailsIfAvailable: Bool { get { UserDefaults.standard.bool(forKey: "hideServiceDetailsIfAvailable") } set { UserDefaults.standard.set(newValue, forKey: "hideServiceDetailsIfAvailable") } } var allowPopupToStretchAsNeeded: Bool { get { UserDefaults.standard.bool(forKey: "allowPopupToStretchAsNeeded") } set { UserDefaults.standard.set(newValue, forKey: "allowPopupToStretchAsNeeded") } } var selectedServices: [ServiceDefinition] { get { let identifiers = UserDefaults.standard.array(forKey: "selectedServices") as? [String] ?? [] // Match the identifiers to our loaded service definitions let definitions = identifiers.map(serviceLoader.serviceDefinition(forIdentifier:)).compactMap { $0 } let sortedDefinitions = definitions.sorted(by: ServiceDefinitionSortByName) return sortedDefinitions } set { let identifiers = newValue.map { $0.globalIdentifier } UserDefaults.standard.set(identifiers, forKey: "selectedServices") } } init(serviceLoader: ServiceLoader) { self.serviceLoader = serviceLoader UserDefaults.standard.register(defaults: [ "notifyOnStatusChange": true, "hideServiceDetailsIfAvailable": false, "allowPopupToStretchAsNeeded": false, "selectedServices": ["CircleCI", "Cloudflare", "GitHub", "NPM", "TravisCI"] ]) Preferences.migrate() } private static func migrate() { // Migrate old names to new names if needed let migrationMapping: [String: String] = [ "CloudFlare": "Cloudflare", // v1.0.0 used the name "CloudFlare" instead of the official "Cloudflare" "Apple": "AppleAll", // Apple changed from one service to multiple sub services "AppleDeveloper": "AppleDeveloperAll", // Apple Developer changed from one service to multiple sub services "VMwareCarbonBlack": "Broadcom", // v2.23 "Tableau": "TableauAll", // v2.23 "Spoke": "Okta", // v2.23 // There were many others but they were migrated to the services.json file // Generated services "FirebaseMLKit": "FirebaseMachineLearning", "AdobeAdobePhotoshopAPI": "AdobePhotoshopAPI" ] if var services = UserDefaults.standard.array(forKey: "selectedServices") as? [String] { for (index, oldClassName) in services.enumerated() { if let newClassName = migrationMapping[oldClassName] { services[index] = newClassName debugPrint("Replaced service \(oldClassName) with \(newClassName)") } } let uniqueServices = Set(services) UserDefaults.standard.setValue(Array(uniqueServices), forKey: "selectedServices") } } } ================================================ FILE: stts/PreferencesWindow/NSAppearance+Extensions.swift ================================================ // // NSAppearance+Extensions.swift // PreferencesWindow // import Cocoa extension NSAppearance { var isDarkMode: Bool { name == .darkAqua || name == .vibrantDark } } ================================================ FILE: stts/PreferencesWindow/PreferencesAboutView.swift ================================================ // // PreferencesAboutView.swift // PreferencesWindow // import Cocoa public struct AboutContent { public struct Link { public let title: String public let url: URL public init(title: String, url: URL) { self.title = title self.url = url } } public let links: [Link] public let credit: String? public init(links: [Link], credit: String? = nil) { self.links = links self.credit = credit } } public class PreferencesAboutView: NSView, PreferencesView { private let content: AboutContent private let appIconView = NSImageView() private let appNameLabel = NSTextField(labelWithString: "") private let versionLabel = NSTextField(labelWithString: "") private var linkButtons: [NSButton] = [] private let creditLabel = NSTextField(wrappingLabelWithString: "") public init(content: AboutContent) { self.content = content super.init(frame: .zero) commonInit() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func commonInit() { appIconView.image = NSApp.applicationIconImage appIconView.widthAnchor.constraint(equalToConstant: 80).isActive = true appIconView.heightAnchor.constraint(equalToConstant: 80).isActive = true let appName = Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String ?? "" appNameLabel.stringValue = appName appNameLabel.font = .systemFont(ofSize: 20, weight: .semibold) let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "" let build = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String ?? "" versionLabel.stringValue = "Version \(version) (\(build))" versionLabel.textColor = .secondaryLabelColor versionLabel.font = .systemFont(ofSize: 12) let divider = NSBox() divider.boxType = .separator linkButtons = content.links.map { link in let button = NSButton(title: link.title, target: self, action: #selector(openLink(_:))) button.bezelStyle = .rounded button.font = .systemFont(ofSize: 13) return button } let buttonRow = NSStackView(views: linkButtons) buttonRow.orientation = .horizontal buttonRow.spacing = 12 creditLabel.stringValue = content.credit ?? "" creditLabel.isHidden = content.credit == nil creditLabel.textColor = .tertiaryLabelColor creditLabel.font = .systemFont(ofSize: 11) creditLabel.alignment = .center let contentStack = NSStackView( views: [appIconView, appNameLabel, versionLabel, divider, buttonRow] ) contentStack.orientation = .vertical contentStack.alignment = .centerX contentStack.spacing = 0 contentStack.translatesAutoresizingMaskIntoConstraints = false contentStack.setCustomSpacing(12, after: appIconView) contentStack.setCustomSpacing(4, after: appNameLabel) contentStack.setCustomSpacing(24, after: versionLabel) contentStack.setCustomSpacing(20, after: divider) creditLabel.translatesAutoresizingMaskIntoConstraints = false addSubview(contentStack) addSubview(creditLabel) NSLayoutConstraint.activate([ widthAnchor.constraint(equalToConstant: 400), heightAnchor.constraint(equalToConstant: 400), contentStack.centerXAnchor.constraint(equalTo: centerXAnchor), contentStack.centerYAnchor.constraint(equalTo: centerYAnchor), divider.widthAnchor.constraint(equalTo: contentStack.widthAnchor, constant: -80), creditLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 40), creditLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -40), creditLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -24) ]) } @objc private func openLink(_ sender: NSButton) { guard let index = linkButtons.firstIndex(of: sender) else { return } NSWorkspace.shared.open(content.links[index].url) } public func willShow() {} } ================================================ FILE: stts/PreferencesWindow/PreferencesSidebarMenu.swift ================================================ // // PreferencesSidebarMenu.swift // PreferencesWindow // import Cocoa import SFSafeSymbols public protocol PreferencesView: NSView { func willShow() } public struct PreferencesSidebarMenuItem: Hashable { public let id = UUID() public let title: String public let symbol: SFSymbol public let view: any PreferencesView public func hash(into hasher: inout Hasher) { hasher.combine(self.id) } public static func == (lhs: PreferencesSidebarMenuItem, rhs: PreferencesSidebarMenuItem) -> Bool { return lhs.id == rhs.id } public init(title: String, symbol: SFSymbol, view: any PreferencesView) { self.title = title self.symbol = symbol self.view = view } } ================================================ FILE: stts/PreferencesWindow/PreferencesWindowController.swift ================================================ // // PreferencesWindowController.swift // PreferencesWindow // import Cocoa import SFSafeSymbols public class PreferencesWindowController: NSWindowController { public let menuItems: [PreferencesSidebarMenuItem] private let sidebarTableView = NSTableView() private let contentContainer = NSView() private var currentView: (any PreferencesView)? private var backHistory: [Int] = [] private var forwardHistory: [Int] = [] private var selectedIndex: Int = 0 private var isNavigating = false private lazy var backButton: NSButton = { NSButton(image: NSImage(systemSymbol: .chevronLeft), target: self, action: #selector(navigateBack)) }() private lazy var forwardButton: NSButton = { NSButton(image: NSImage(systemSymbol: .chevronRight), target: self, action: #selector(navigateForward)) }() private lazy var titleLabel: NSTextField = { let label = NSTextField(labelWithString: "") label.font = .systemFont(ofSize: 15, weight: .semibold) label.alignment = .natural return label }() public init(menuItems: [PreferencesSidebarMenuItem]) { self.menuItems = menuItems let window = NSWindow() window.styleMask = [.titled, .fullSizeContentView, .closable, .miniaturizable, .resizable] window.titleVisibility = .hidden window.titlebarSeparatorStyle = .automatic super.init(window: window) setup() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func setup() { let toolbar = NSToolbar(identifier: "PreferencesToolbar") toolbar.delegate = self toolbar.displayMode = .iconOnly window?.toolbar = toolbar window?.toolbarStyle = .unified let sidebarVC = NSViewController() sidebarVC.view = makeSidebarScrollView() let sidebarItem = NSSplitViewItem(sidebarWithViewController: sidebarVC) sidebarItem.canCollapse = false sidebarItem.minimumThickness = 160 sidebarItem.maximumThickness = 200 let contentVC = NSViewController() contentVC.view = contentContainer let contentItem = NSSplitViewItem(viewController: contentVC) contentItem.canCollapse = false let splitVC = NSSplitViewController() splitVC.splitViewItems = [sidebarItem, contentItem] contentViewController = splitVC if !menuItems.isEmpty { sidebarTableView.selectRowIndexes(.init(integer: 0), byExtendingSelection: false) selectItem(at: 0, addingToHistory: false) } } private func makeSidebarScrollView() -> NSView { let scrollView = NSScrollView() scrollView.borderType = .noBorder scrollView.drawsBackground = false scrollView.hasVerticalScroller = true scrollView.hasHorizontalScroller = false let column = NSTableColumn(identifier: .init("item")) column.resizingMask = .autoresizingMask sidebarTableView.addTableColumn(column) sidebarTableView.headerView = nil sidebarTableView.style = .sourceList sidebarTableView.backgroundColor = .clear sidebarTableView.focusRingType = .none sidebarTableView.rowHeight = 32 sidebarTableView.dataSource = self sidebarTableView.delegate = self scrollView.documentView = sidebarTableView return scrollView } private func selectItem(at index: Int, addingToHistory: Bool) { if addingToHistory, index != selectedIndex { backHistory.append(selectedIndex) forwardHistory.removeAll() } selectedIndex = index showView(menuItems[index].view) updateNavigationState() } private func showView(_ view: any PreferencesView) { currentView?.removeFromSuperview() currentView = view view.willShow() view.translatesAutoresizingMaskIntoConstraints = false contentContainer.addSubview(view) NSLayoutConstraint.activate([ view.topAnchor.constraint(equalTo: contentContainer.topAnchor), view.leadingAnchor.constraint(equalTo: contentContainer.leadingAnchor), view.trailingAnchor.constraint(equalTo: contentContainer.trailingAnchor), view.bottomAnchor.constraint(equalTo: contentContainer.bottomAnchor) ]) } private func updateNavigationState() { backButton.isEnabled = !backHistory.isEmpty forwardButton.isEnabled = !forwardHistory.isEmpty titleLabel.stringValue = menuItems[selectedIndex].title } @objc private func navigateBack() { guard let previous = backHistory.popLast() else { return } forwardHistory.append(selectedIndex) selectedIndex = previous syncSidebarSelection(to: previous) showView(menuItems[previous].view) updateNavigationState() } @objc private func navigateForward() { guard let next = forwardHistory.popLast() else { return } backHistory.append(selectedIndex) selectedIndex = next syncSidebarSelection(to: next) showView(menuItems[next].view) updateNavigationState() } private func syncSidebarSelection(to index: Int) { isNavigating = true sidebarTableView.selectRowIndexes(.init(integer: index), byExtendingSelection: false) isNavigating = false } public func show() { NSApplication.shared.activate(ignoringOtherApps: true) let alreadyVisible = window?.isVisible == true showWindow(nil) if !alreadyVisible { window?.center() } DispatchQueue.main.async { [weak self] in NSApplication.shared.activate(ignoringOtherApps: true) self?.window?.makeKeyAndOrderFront(nil) } } } // MARK: - NSToolbarDelegate extension PreferencesWindowController: NSToolbarDelegate { public func toolbar( _ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool ) -> NSToolbarItem? { switch itemIdentifier.rawValue { case "PreferencesNavigate": for button in [backButton, forwardButton] { button.isBordered = true button.bezelStyle = .texturedRounded button.isEnabled = false button.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ button.widthAnchor.constraint(equalToConstant: 32), button.heightAnchor.constraint(equalToConstant: 32) ]) } let separator = NSBox() separator.boxType = .separator separator.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ separator.widthAnchor.constraint(equalToConstant: 1), separator.heightAnchor.constraint(equalToConstant: 18) ]) let navView = NSStackView(views: [backButton, separator, forwardButton]) navView.spacing = -1 navView.orientation = .horizontal let item = NSToolbarItem(itemIdentifier: itemIdentifier) item.view = navView item.label = "Navigate" return item case "PreferencesTitle": let item = NSToolbarItem(itemIdentifier: itemIdentifier) item.view = titleLabel return item default: return nil } } public func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { [.init("PreferencesNavigate"), .init("PreferencesTitle"), .flexibleSpace] } public func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { [ .init("PreferencesNavigate"), .init("PreferencesTitle"), .flexibleSpace, .space ] } } // MARK: - NSTableViewDataSource extension PreferencesWindowController: NSTableViewDataSource { public func numberOfRows(in tableView: NSTableView) -> Int { menuItems.count } } // MARK: - NSTableViewDelegate extension PreferencesWindowController: NSTableViewDelegate { public func tableView( _ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int ) -> NSView? { let identifier = NSUserInterfaceItemIdentifier("PreferencesSidebarCell") let cell = tableView.makeView(withIdentifier: identifier, owner: nil) as? NSTableCellView ?? { let cell = NSTableCellView() cell.identifier = identifier let imageView = NSImageView() imageView.translatesAutoresizingMaskIntoConstraints = false imageView.symbolConfiguration = .init(pointSize: 14, weight: .medium) cell.imageView = imageView cell.addSubview(imageView) let textField = NSTextField(labelWithString: "") textField.translatesAutoresizingMaskIntoConstraints = false textField.font = .preferredFont(forTextStyle: .body) textField.lineBreakMode = .byTruncatingTail cell.textField = textField cell.addSubview(textField) NSLayoutConstraint.activate([ imageView.leadingAnchor.constraint(equalTo: cell.leadingAnchor, constant: 4), imageView.centerYAnchor.constraint(equalTo: cell.centerYAnchor), imageView.widthAnchor.constraint(equalToConstant: 20), imageView.heightAnchor.constraint(equalToConstant: 20), textField.leadingAnchor.constraint(equalTo: imageView.trailingAnchor, constant: 6), textField.centerYAnchor.constraint(equalTo: cell.centerYAnchor), textField.trailingAnchor.constraint(equalTo: cell.trailingAnchor, constant: -4) ]) return cell }() let item = menuItems[row] cell.imageView?.image = NSImage(systemSymbol: item.symbol) cell.textField?.stringValue = item.title return cell } public func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat { 32 } public func tableViewSelectionDidChange(_ notification: Notification) { guard !isNavigating, sidebarTableView.selectedRow >= 0 else { return } selectItem(at: sidebarTableView.selectedRow, addingToHistory: true) } } ================================================ FILE: stts/ServiceLoader/AppDefinedServiceDefinitionProvider.swift ================================================ // // AppDefinedServiceDefinitionProvider.swift // stts // import Foundation enum AppDefinedServiceDefinitionProviderError: Error { case bundleServicesJSONNotFound } class AppDefinedServiceDefinitionProvider: JSONBasedServiceDefinitionProvider { init() throws { guard let bundleServicesJSONPath = Bundle.main.path(forResource: "services", ofType: "json") else { assertionFailure("Could not find services.json in the bundle") throw AppDefinedServiceDefinitionProviderError.bundleServicesJSONNotFound } super.init(path: bundleServicesJSONPath, required: true) } } ================================================ FILE: stts/ServiceLoader/BundleServiceDefinitionProvider.swift ================================================ // // BundleServiceDefinitionProvider.swift // stts // import Foundation enum BundleServiceDefinitionProviderError: Error { case bundledServicesPlistNotFound case bundledServicesPlistWrongFormat } class BundleServiceDefinitionProvider: ClassBasedServiceDefinitionProvider { init() throws { guard let servicesPlist = Bundle.main.path(forResource: "services", ofType: "plist") else { throw BundleServiceDefinitionProviderError.bundledServicesPlistNotFound } guard let classNames = NSDictionary(contentsOfFile: servicesPlist)?["services"] as? [String] else { throw BundleServiceDefinitionProviderError.bundledServicesPlistWrongFormat } super.init(classNames: classNames) } } ================================================ FILE: stts/ServiceLoader/ServiceDefinition.swift ================================================ // // ServiceDefinition.swift // stts // import Foundation protocol ServiceDefinition: CodableServiceDefinition { /// Identifier of the provider of the status page (e.g. statuspage, statuspal, cachet, instatus, etc.) /// For use in local storage. var providerIdentifier: String { get } /// Identifier for this service for use in local storage. /// This is how it was stored before switching to JSON definitions var legacyIdentifiers: Set { get } /// Identifier for this service for use in local storage. var globalIdentifier: String { get } /// Builds the service object from the definition. func build() -> BaseService? } extension ServiceDefinition { var globalIdentifier: String { "\(providerIdentifier).\(alphanumericName)" } func eq(_ other: ServiceDefinition) -> Bool { globalIdentifier == other.globalIdentifier } } let ServiceDefinitionSortByName: (ServiceDefinition, ServiceDefinition) -> Bool = { a, b in a.name.localizedCaseInsensitiveCompare(b.name) == .orderedAscending } class CodableServiceDefinition: Codable { enum CodingKeys: String, CodingKey { case name case url case isCategory = "category" case isSubService = "subservice" case oldNames = "old_names" } let name: String let url: URL let isCategory: Bool? let isSubService: Bool? let oldNames: Set? private(set) lazy var legacyIdentifiers = oldNames ?? .init() var alphanumericName: String { String(name.unicodeScalars.filter(CharacterSet.alphanumerics.contains)) } init(name: String, url: URL, isCategory: Bool?, isSubService: Bool?, oldNames: Set? = nil) { assert(type(of: self) != CodableServiceDefinition.self) self.oldNames = oldNames self.name = name self.isCategory = isCategory self.isSubService = isSubService self.url = url } required init(from decoder: Decoder) throws { assert(type(of: self) != CodableServiceDefinition.self) let container = try decoder.container(keyedBy: CodingKeys.self) self.name = try container.decode(String.self, forKey: .name) self.url = try container.decode(URL.self, forKey: .url) self.isCategory = try container.decodeIfPresent(Bool.self, forKey: .isCategory) self.isSubService = try container.decodeIfPresent(Bool.self, forKey: .isSubService) self.oldNames = try container.decodeIfPresent(Set.self, forKey: .oldNames) } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(self.name, forKey: .name) try container.encode(self.url, forKey: .url) try container.encodeIfPresent(self.isCategory, forKey: .isCategory) try container.encodeIfPresent(self.isSubService, forKey: .isSubService) try container.encodeIfPresent(self.oldNames, forKey: .oldNames) } } ================================================ FILE: stts/ServiceLoader/ServiceDefinitionProvider.swift ================================================ // // ServiceDefinitionProvider.swift // stts // import Foundation protocol ServiceDefinitionProvider { func definedServices() throws -> [ServiceDefinition]? } class JSONBasedServiceDefinitionProvider: ServiceDefinitionProvider { private let path: String let required: Bool init(path: String, required: Bool) { self.path = path self.required = required } func definedServices() throws -> [ServiceDefinition]? { do { let jsonData = try Data(contentsOf: URL(fileURLWithPath: path)) let decodedServices = try JSONDecoder().decode(ServicesStructure.self, from: jsonData) return decodedServices.allServices } catch { if required { throw error } else { return [] } } } } class ClassBasedServiceDefinitionProvider: ServiceDefinitionProvider { private let classNames: [String] init(classNames: [String]) { self.classNames = classNames } func definedServices() throws -> [ServiceDefinition]? { classNames.compactMap { IndependentServiceDefinition(fromClassName: $0) } } } ================================================ FILE: stts/ServiceLoader/ServiceLoader.swift ================================================ // // ServiceLoader.swift // stts // import Foundation final class ServiceLoader { private let providers: [ServiceDefinitionProvider] init(providers: [ServiceDefinitionProvider]) { self.providers = providers } private(set) lazy var allServices: [ServiceDefinition] = { var uniqueServiceIdentifiers = Set() var serviceDefinitions = [ServiceDefinition]() var uniqueAppend: ([ServiceDefinition]) -> Void = { definitions in definitions.forEach { definition in guard !uniqueServiceIdentifiers.contains(definition.globalIdentifier) else { return } uniqueServiceIdentifiers.insert(definition.globalIdentifier) serviceDefinitions.append(definition) } } for provider in providers { // swiftlint:disable:next force_try if let providerDefinitions = try! provider.definedServices() { uniqueAppend(providerDefinitions) } } return serviceDefinitions.sorted(by: ServiceDefinitionSortByName) }() private(set) lazy var allServicesWithoutSubServices: [ServiceDefinition] = { allServices.filter { !($0.isSubService == true) } }() func services(for definitions: [ServiceDefinition]) -> [BaseService] { definitions.compactMap { $0.build() } } func serviceDefinition(forIdentifier identifier: String) -> ServiceDefinition? { allServices.first { $0.globalIdentifier == identifier || // The recommended way for identifying services $0.alphanumericName.lowercased() == identifier.lowercased() || // The old way (class-name based) $0.legacyIdentifiers.contains(identifier) // The old names used for a service } } } ================================================ FILE: stts/ServiceLoader/ServicesStructure.swift ================================================ // // ServicesStructure.swift // stts // import Foundation struct ServicesStructure: Codable { enum CodingKeys: String, CodingKey { case independentServices = "independent" case cachetServices = "cachet" case lambServices = "lamb" case sorryServices = "sorry" case statusCakeServices = "statuscake" case statusPageServices = "statuspage" case instatusServices = "instatus" case statusCastServices = "statuscast" case incidentIOServices = "incidentio" case statusioV1Services = "statusiov1" case statuspalServices = "statuspal" case site24x7Services = "site24x7" case cstateServices = "cstate" case statusHubServices = "statushub" case betterUptimeServices = "betteruptime" case betterStackServices = "betterstack" case sendbirdServices = "sendbird" case miroServices = "miro" } let independentServices: [IndependentServiceDefinition]? let cachetServices: [CachetServiceDefinition]? let lambServices: [LambStatusServiceDefinition]? let sorryServices: [SorryServiceDefinition]? let statusCakeServices: [StatusCakeServiceDefinition]? let statusPageServices: [StatusPageServiceDefinition]? let instatusServices: [InstatusServiceDefinition]? let statusCastServices: [StatusCastServiceDefinition]? let incidentIOServices: [IncidentIOServiceDefinition]? let statusioV1Services: [StatusioV1ServiceDefinition]? let statuspalServices: [StatuspalServiceDefinition]? let site24x7Services: [Site24x7ServiceDefinition]? let cstateServices: [CStateServiceDefinition]? let statusHubServices: [StatusHubServiceDefinition]? let betterUptimeServices: [BetterUptimeServiceDefinition]? let betterStackServices: [BetterStackServiceDefinition]? let sendbirdServices: [SendbirdServiceDefinition]? let miroServices: [MiroServiceDefinition]? var allServices: [ServiceDefinition] { let sections: [[ServiceDefinition]?] = [ independentServices, cachetServices, lambServices, sorryServices, statusCakeServices, statusPageServices, instatusServices, statusCastServices, incidentIOServices, statusioV1Services, statuspalServices, site24x7Services, cstateServices, statusHubServices, betterUptimeServices, betterStackServices, sendbirdServices, miroServices ] return sections.compactMap { $0 }.flatMap { $0 } } } ================================================ FILE: stts/ServiceLoader/UserDefinedServiceDefinitionProvider.swift ================================================ // // UserDefinedServiceDefinitionProvider.swift // stts // import Foundation // swiftlint:disable:next type_name enum UserDefinedServiceDefinitionProviderError: Error { case applicationSupportDirectoryNotFound } class UserDefinedServiceDefinitionProvider: JSONBasedServiceDefinitionProvider { init() throws { guard let applicationSupportURL = FileManager.default.urls( for: .applicationSupportDirectory, in: .userDomainMask ).first else { assertionFailure("Could not find Application Support folder") throw UserDefinedServiceDefinitionProviderError.applicationSupportDirectoryNotFound } let sttsAppSupportURL = applicationSupportURL.appendingPathComponent("stts") try FileManager.default.createDirectory( at: sttsAppSupportURL, withIntermediateDirectories: true, attributes: nil ) let servicesJSONPath = sttsAppSupportURL.appendingPathComponent("services.json").path super.init(path: servicesJSONPath, required: false) } } ================================================ FILE: stts/ServiceTableView/ServiceTableRowView.swift ================================================ // // ServiceTableRowView.swift // stts // import Cocoa class ServiceTableRowView: NSTableRowView { var showSeparator = true var gradient: CAGradientLayer? private var effectViewBackground: NSVisualEffectView? var usesWindowBackground: Bool = false { didSet { if usesWindowBackground { let effectView = effectViewBackground ?? NSVisualEffectView() effectView.translatesAutoresizingMaskIntoConstraints = false effectView.material = .windowBackground effectView.blendingMode = .withinWindow effectViewBackground = effectView if effectView.superview == nil { addSubview(effectView) NSLayoutConstraint.activate([ effectView.topAnchor.constraint(equalTo: topAnchor), effectView.leadingAnchor.constraint(equalTo: leadingAnchor), effectView.trailingAnchor.constraint(equalTo: trailingAnchor), effectView.bottomAnchor.constraint(equalTo: bottomAnchor) ]) } } else { effectViewBackground?.removeFromSuperview() } } } override func layout() { super.layout() let width = frame.size.width let height = frame.size.height let gradient = self.gradient ?? CAGradientLayer() gradient.isHidden = !showSeparator self.wantsLayer = true self.layer?.insertSublayer(gradient, at: 0) self.gradient = gradient let separatorColor = NSColor.quaternaryLabelColor.cgColor gradient.colors = [NSColor.clear.cgColor, separatorColor, separatorColor, separatorColor, NSColor.clear.cgColor] gradient.locations = [0, 0.3, 0.5, 0.70, 1] gradient.startPoint = CGPoint(x: 0, y: 0.5) gradient.endPoint = CGPoint(x: 1, y: 0.5) gradient.frame = CGRect(x: 0, y: height - 1, width: width, height: 1) } } ================================================ FILE: stts/ServiceTableView/ServiceTableViewController.swift ================================================ // // ServiceTableViewController.swift // stts // import Cocoa import MBPopup import PreferencesWindow class ServiceTableViewController: NSObject, SwitchableTableViewController { let contentView = NSStackView(frame: CGRect(x: 0, y: 0, width: 280, height: 400)) let scrollView = CustomScrollView() let tableView = NSTableView() let bottomBar = BottomBar() let addServicesNoticeField = NSTextField() private let serviceLoader: ServiceLoader var services: [BaseService] = [] private let preferences: Preferences private let preferencesWindow: PreferencesWindow @Atomic var servicesBeingUpdated = Set() var generalStatus: ServiceStatus { let hasBadServices = services.first { $0.status > .maintenance } != nil return hasBadServices ? .major : .good } var hidden: Bool = false var updateCallback: (() -> Void)? init(serviceLoader: ServiceLoader, preferences: Preferences, preferencesWindow: PreferencesWindow) { self.serviceLoader = serviceLoader self.preferences = preferences self.preferencesWindow = preferencesWindow super.init() reloadServicesList() } func setup() { bottomBar.reloadServicesCallback = (NSApp.delegate as? AppDelegate)!.updateServices bottomBar.openSettingsCallback = { [weak self] in self?.preferencesWindow.show() } guard let superview = contentView.superview else { assertionFailure("Add contentView to another view before calling setup()") return } contentView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ contentView.leadingAnchor.constraint(equalTo: superview.leadingAnchor), contentView.trailingAnchor.constraint(equalTo: superview.trailingAnchor), contentView.bottomAnchor.constraint(equalTo: superview.bottomAnchor), contentView.widthAnchor.constraint(greaterThanOrEqualToConstant: 220), // tableView.rowHeight + bottomBar.frame.size.height + 2 contentView.heightAnchor.constraint(greaterThanOrEqualToConstant: 40 + 36 + 2) ]) [scrollView, bottomBar, addServicesNoticeField].forEach { $0.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview($0) } let scrollViewTopConstraint = scrollView.topAnchor.constraint(equalTo: contentView.topAnchor) scrollView.topConstraint = scrollViewTopConstraint NSLayoutConstraint.activate([ scrollViewTopConstraint, scrollView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), scrollView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), bottomBar.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), bottomBar.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), bottomBar.topAnchor.constraint(equalTo: scrollView.bottomAnchor), bottomBar.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), bottomBar.heightAnchor.constraint(equalToConstant: 36), addServicesNoticeField.heightAnchor.constraint(equalToConstant: 22), addServicesNoticeField.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), addServicesNoticeField.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), addServicesNoticeField.centerYAnchor.constraint(equalTo: contentView.centerYAnchor, constant: -14) ]) scrollView.borderType = .noBorder scrollView.hasVerticalScroller = true scrollView.hasHorizontalScroller = false scrollView.autoresizesSubviews = true scrollView.documentView = tableView scrollView.drawsBackground = false scrollView.wantsLayer = true scrollView.layer?.cornerRadius = 6 tableView.frame = scrollView.bounds let column = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(rawValue: "serviceColumnIdentifier")) column.width = tableView.frame.size.width tableView.addTableColumn(column) tableView.autoresizesSubviews = true tableView.wantsLayer = true tableView.layer?.cornerRadius = 6 tableView.headerView = nil tableView.gridStyleMask = NSTableView.GridLineStyle.init(rawValue: 0) tableView.dataSource = self tableView.delegate = self tableView.selectionHighlightStyle = .none tableView.backgroundColor = NSColor.clear tableView.style = .fullWidth addServicesNoticeField.isEditable = false addServicesNoticeField.isBordered = false addServicesNoticeField.isSelectable = false let italicFont = NSFontManager.shared.font( withFamily: NSFont.systemFont(ofSize: 13).fontName, traits: NSFontTraitMask.italicFontMask, weight: 5, size: 13 ) addServicesNoticeField.font = italicFont addServicesNoticeField.textColor = NSColor.textColor addServicesNoticeField.maximumNumberOfLines = 1 addServicesNoticeField.cell!.truncatesLastVisibleLine = true addServicesNoticeField.alignment = .center addServicesNoticeField.stringValue = "Maybe enable some services? :)" addServicesNoticeField.backgroundColor = .clear } func willOpenPopup() { resizeViews() reloadData() if case let .updated(date) = bottomBar.status { if Date().timeIntervalSince1970 - date.timeIntervalSince1970 > 60 { (NSApp.delegate as? AppDelegate)?.updateServices() } } } func willShow() { scrollView.topConstraint?.constant = 0 scrollView.documentView = tableView addServicesNoticeField.isHidden = services.count > 0 resizeViews() } func willHide() { addServicesNoticeField.isHidden = true } func resizeViews() { let maxHeight: CGFloat if preferences.allowPopupToStretchAsNeeded, let usableHeight = NSScreen.usableHeightOfActiveScreen { maxHeight = usableHeight - 32 // To accommodate for the popup's arrow/background } else { maxHeight = 490 } scrollView.frame.size.height = min(tableView.intrinsicContentSize.height, maxHeight) (NSApp.delegate as? AppDelegate)?.popupController.resizePopup( height: scrollView.frame.size.height + bottomBar.frame.size.height ) } func reloadServicesList() { services = serviceLoader.services(for: preferences.selectedServices) reloadData() addServicesNoticeField.isHidden = services.count > 0 } func reloadData(at index: Int? = nil) { services.sort() bottomBar.updateStatusText() guard index != nil else { tableView.reloadData() return } tableView.reloadData(forRowIndexes: IndexSet(integer: index!), columnIndexes: IndexSet(integer: 0)) } func updateServices(updateCallback: @escaping () -> Void) { servicesBeingUpdated = Set() guard !services.isEmpty else { reloadData() bottomBar.status = .updated(Date()) self.updateCallback?() self.updateCallback = nil resizeViews() return } self.updateCallback = updateCallback bottomBar.status = .updating let servicesToUpdate = Set(services) servicesBeingUpdated = servicesToUpdate Task { [weak self] in await withTaskGroup(of: Void.self) { [weak self] group in for service in servicesToUpdate { group.addTask { [weak self] in await service.updateStatusAutomaticallyHandlingErrors() await self?.updatedStatus(for: service) } } } } } @MainActor private func updatedStatus(for service: BaseService) async { servicesBeingUpdated.remove(service) reloadData() resizeViews() if servicesBeingUpdated.isEmpty { bottomBar.status = .updated(Date()) updateCallback?() updateCallback = nil } } } extension ServiceTableViewController: NSTableViewDataSource { func numberOfRows(in tableView: NSTableView) -> Int { return services.count } func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { return nil } } extension ServiceTableViewController: NSTableViewDelegate { func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { let identifier = tableColumn?.identifier ?? NSUserInterfaceItemIdentifier(rawValue: "identifier") let cell = tableView.makeView(withIdentifier: identifier, owner: self) ?? StatusTableCell() guard let view = cell as? StatusTableCell else { return nil } guard let service = services[row] as? Service else { return nil } view.setup(with: service, preferences: preferences) return view } func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? { let cellIdentifier = NSUserInterfaceItemIdentifier(rawValue: "rowView") let cell = tableView.makeView(withIdentifier: cellIdentifier, owner: self) ?? ServiceTableRowView() guard let view = cell as? ServiceTableRowView else { return nil } view.showSeparator = row + 1 < services.count return view } func tableView(_ tableView: NSTableView, shouldSelectRow row: Int) -> Bool { guard let service = services[row] as? Service else { return false } NSWorkspace.shared.open(service.url) return false } func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat { guard let service = services[row] as? Service else { return 40 } return StatusTableCell.Layout.heightOfRow( for: service, preferences: preferences, width: tableView.frame.size.width - 3 // tableview padding is 3 ) } } ================================================ FILE: stts/ServiceTableView/StatusIndicator.swift ================================================ // // StatusIndicator.swift // stts // import Cocoa class StatusIndicator: NSView { var checkmarkIcon = CheckmarkIcon() var crossIcon = CrossIcon() var status: ServiceStatus = .good { didSet { checkmarkIcon.isHidden = status > .maintenance || status == .undetermined crossIcon.isHidden = status <= .maintenance && status != .undetermined switch status { case .good: checkmarkIcon.color = StatusColor.green case .notice: checkmarkIcon.color = StatusColor.green case .maintenance: checkmarkIcon.color = StatusColor.blue case .minor: crossIcon.color = StatusColor.orange case .major: crossIcon.color = StatusColor.red case .undetermined: crossIcon.color = StatusColor.gray } } } init() { super.init(frame: NSRect.zero) commonInit() } required init?(coder: NSCoder) { super.init(coder: coder) commonInit() } private func commonInit() { addSubview(checkmarkIcon) addSubview(crossIcon) } override func setFrameSize(_ newSize: NSSize) { super.setFrameSize(newSize) checkmarkIcon.frame = bounds crossIcon.frame = bounds } } class StatusColor { static var green = NSColor(calibratedRed: 0.36, green: 0.68, blue: 0.46, alpha: 1) static var blue = NSColor(calibratedRed: 0.24, green: 0.54, blue: 1, alpha: 0.8) static var orange = NSColor.orange static var red = NSColor(calibratedRed: 0.9, green: 0.4, blue: 0.23, alpha: 1) static var gray = NSColor.tertiaryLabelColor } ================================================ FILE: stts/ServiceTableView/StatusTableCell.swift ================================================ // // StatusTableCell.swift // stts // import Cocoa class StatusTableCell: NSTableCellView { let statusIndicator = StatusIndicator() let stackView = NSStackView() let titleField = NSTextField() let statusField = NSTextField() enum Layout { static let verticalPadding: CGFloat = 10 static let verticalSpacing: CGFloat = 4 static let horizontalPadding: CGFloat = 8 static let horizontalSpacing: CGFloat = 8 static let titleFont = NSFont.systemFont(ofSize: 13) static let messageFont = NSFontManager.shared.font( withFamily: titleFont.fontName, traits: NSFontTraitMask.italicFontMask, weight: 5, size: 11 ) static let statusIndicatorSize = CGSize(width: 14, height: 14) private static let dummyCell = StatusTableCell(frame: .zero) static func heightOfRow(for service: Service, preferences: Preferences, width: CGFloat) -> CGFloat { let nsScrollerWidth: CGFloat = 16 let realRowWidth = width - (nsScrollerWidth - 4) // 4 by trial & error dummyCell.frame.size = CGSize(width: realRowWidth, height: 400) dummyCell.setup(with: service, preferences: preferences) dummyCell.layoutSubtreeIfNeeded() return dummyCell.stackView.frame.size.height + (verticalPadding * 2) } } override init(frame frameRect: NSRect) { super.init(frame: frameRect) commonInit() } required init?(coder: NSCoder) { super.init(coder: coder) commonInit() } private func commonInit() { textField?.removeFromSuperview() statusIndicator.scaleUnitSquare(to: NSSize(width: 0.3, height: 0.3)) statusIndicator.translatesAutoresizingMaskIntoConstraints = false addSubview(statusIndicator) stackView.orientation = .vertical stackView.distribution = .fill stackView.alignment = .leading stackView.spacing = Layout.verticalSpacing stackView.translatesAutoresizingMaskIntoConstraints = false addSubview(stackView) titleField.isEditable = false titleField.isBordered = false titleField.isSelectable = false titleField.maximumNumberOfLines = 2 titleField.cell!.truncatesLastVisibleLine = true titleField.cell!.lineBreakMode = .byWordWrapping titleField.cell!.wraps = true titleField.font = Layout.titleFont titleField.textColor = NSColor.labelColor titleField.backgroundColor = NSColor.clear statusField.isEditable = false statusField.isBordered = false statusField.isSelectable = false statusField.font = Layout.messageFont statusField.textColor = NSColor.secondaryLabelColor statusField.maximumNumberOfLines = 6 statusField.cell!.truncatesLastVisibleLine = true statusField.cell!.lineBreakMode = .byWordWrapping statusField.cell!.wraps = true statusField.backgroundColor = NSColor.clear [titleField, statusField].forEach { stackView.addArrangedSubview($0) } NSLayoutConstraint.activate([ statusIndicator.heightAnchor.constraint(equalToConstant: Layout.statusIndicatorSize.height), statusIndicator.widthAnchor.constraint(equalToConstant: Layout.statusIndicatorSize.height), statusIndicator.leadingAnchor.constraint(equalTo: leadingAnchor, constant: Layout.horizontalPadding), statusIndicator.centerYAnchor.constraint(equalTo: centerYAnchor), stackView.leadingAnchor.constraint( equalTo: statusIndicator.trailingAnchor, constant: Layout.horizontalSpacing ), stackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -Layout.horizontalPadding), stackView.topAnchor.constraint(equalTo: topAnchor, constant: Layout.verticalPadding), stackView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -Layout.verticalPadding) ]) } func setup(with service: Service, preferences: Preferences) { titleField.stringValue = service.name statusIndicator.status = service.status statusField.stringValue = service.message statusField.isHidden = service.status == .good && preferences.hideServiceDetailsIfAvailable } } ================================================ FILE: stts/Services/Algolia.swift ================================================ // // Algolia.swift // stts // import Foundation import Kanna class Algolia: IndependentService { private enum AlgoliaStatus: String { case operational case majorOutage = "major_outage" case degradedPerformance = "degraded_performance" case partialOutage = "partial_outage" var serviceStatus: ServiceStatus { switch self { case .operational: return .good case .majorOutage: return .major case .degradedPerformance, .partialOutage: return .minor } } var statusMessage: String { switch self { case .operational: return "Operational" case .majorOutage: return "Major outage" case .degradedPerformance: return "Degraded performance" case .partialOutage: return "Partial outage" } } var serviceDescription: ServiceStatusDescription { ServiceStatusDescription(status: serviceStatus, message: statusMessage) } } let url = URL(string: "https://status.algolia.com")! override func updateStatus() async throws { let apiURL = URL(string: "https://status.algolia.com/2/status/service/all/period/current")! let data = try await rawData(from: apiURL) guard let dict = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any], let statusDict = dict["global"] as? [String: Any], let statusString = statusDict["status"] as? String, let status = AlgoliaStatus(rawValue: statusString) else { throw StatusUpdateError.decodingError(nil) } statusDescription = status.serviceDescription } } ================================================ FILE: stts/Services/AzureAll.swift ================================================ // // AzureAll.swift // stts // import Foundation class AzureAll: Azure, ServiceCategory { let categoryName = "Azure" let subServiceSuperclass: AnyObject.Type = BaseAzure.self let name = "Azure (All Regions)" let zoneIdentifier = "*" } ================================================ FILE: stts/Services/AzureDevOpsAll.swift ================================================ // // AzureDevOpsAll.swift // stts // import Foundation class AzureDevOpsAll: AzureDevOps, ServiceCategory { let categoryName = "Azure DevOps" let subServiceSuperclass: AnyObject.Type = BaseAzureDevOps.self let name = "Azure DevOps (All)" let serviceName = "*" } ================================================ FILE: stts/Services/Beanstalk.swift ================================================ // // Beanstalk.swift // stts // import Foundation import Kanna class Beanstalk: IndependentService { let url = URL(string: "https://status.beanstalkapp.com")! override func updateStatus() async throws { let doc = try await html(from: url) let status = status(from: doc) statusDescription = ServiceStatusDescription( status: status, message: message(for: status) ) } } extension Beanstalk { fileprivate func status(from document: HTMLDocument) -> ServiceStatus { let firstStatus = document.css("#updates article:first .status").compactMap { $0.text }.first guard let status = firstStatus else { return .undetermined } switch status { case "ok", "pending": return .good case "maintenance": return .maintenance case "problem": return .major default: return .undetermined } } fileprivate func message(for status: ServiceStatus) -> String { switch status { case .good: return "Services operating normally." case .major: return "Experiencing service interruptions." case .maintenance: return "Scheduled maintenance in progress." default: return "Unexpected response" } } } ================================================ FILE: stts/Services/Broadcom.swift ================================================ // // Broadcom.swift // stts // import Foundation class Broadcom: IndependentService { let url = URL(string: "https://status.broadcom.com")! private struct Response: Codable { let page: Page struct Page: Codable { let state: State let stateText: String? // null when under maintenance enum State: String, Codable { case operational case degraded case underMaintenanceOfficial = "under_maintenance" // as defined in their API spec case underMaintenanceActual = "under-maintenance" // as actually delivered by their API } enum CodingKeys: String, CodingKey { case state case stateText = "state_text" } } } override func updateStatus() async throws { let apiURL = URL(string: "https://status.broadcom.com/api/v1/status")! let response = try await decoded(Response.self, from: apiURL) let status: ServiceStatus switch response.page.state { case .operational: status = .good case .degraded: status = .major case .underMaintenanceOfficial, .underMaintenanceActual: status = .maintenance } let stateText: String if let text = response.page.stateText { stateText = text } else { switch status { case .good: stateText = "All systems are go!" case .maintenance: stateText = "Under maintenance" case .major: stateText = "Degraded" default: stateText = "No status description" } } statusDescription = ServiceStatusDescription(status: status, message: stateText) } } ================================================ FILE: stts/Services/Evernote.swift ================================================ // // Evernote.swift // stts // import Foundation import Kanna class Evernote: IndependentService { let url = URL(string: "https://status.evernote.com")! override func updateStatus() async throws { let doc = try await html(from: url) statusDescription = status(from: doc) } } extension Evernote { fileprivate func status(from document: HTMLDocument) -> ServiceStatusDescription { guard let mostRecentPost = document.css(".post h3").first?.text else { return ServiceStatusDescription(status: .undetermined, message: "Unexpected response") } if mostRecentPost.hasPrefix("[ok]") { return ServiceStatusDescription(status: .good, message: mostRecentPost) } else if mostRecentPost.hasPrefix("[!]") { return ServiceStatusDescription(status: .major, message: mostRecentPost) } else { return ServiceStatusDescription(status: .maintenance, message: mostRecentPost) } } } ================================================ FILE: stts/Services/Fastly.swift ================================================ // // Fastly.swift // stts import Foundation import Kanna class Fastly: IndependentService { let url = URL(string: "https://www.fastlystatus.com")! private enum Status: String, CaseIterable { case available case informational case maintenance case degraded case unavailable case investigating case identified case monitoring var serviceStatus: ServiceStatus { switch self { case .available: return .good case .informational, .identified, .monitoring: return .notice case .maintenance: return .maintenance case .degraded, .investigating: return .minor case .unavailable: return .major } } var displayText: String { switch self { case .available: return "Normal" case .informational: return "Informational" case .maintenance: return "Maintenance" case .degraded: return "Degraded" case .unavailable: return "Unavailable" case .investigating: return "Investigating" case .identified: return "Identified" case .monitoring: return "Monitoring" } } } // Geographic region names used in the Platform tab — replaced with their parent tab name in messages. private static let geographicRegionNames: Set = [ "North America", "Latin America", "Europe", "Asia", "South America", "Oceania", "Africa" ] override func updateStatus() async throws { let doc = try await html(from: url) // Parse tab navigation to build a pid → tab name map. // Tab hrefs end with the component group ID, e.g. "#tab--510166". var tabNames: [String: String] = [:] doc.css("a[data-toggle='tab']").forEach { link in guard let href = link["href"], let tabID = href.components(separatedBy: "-").last, let text = link.text?.trimmingCharacters(in: .whitespacesAndNewlines), !text.isEmpty else { return } tabNames[tabID] = text } // The page shows a history grid where top-level rows have a simple data-path (no dashes) // and the first data column (index 2) shows the current day's status. var componentStatuses: [(name: String, status: Status)] = [] doc.css("tr[data-path]").forEach { row in guard let path = row["data-path"], !path.contains("-") else { return } let tds = Array(row.css("td")) guard tds.count > 2 else { return } let currentTd = tds[2] guard let icon = currentTd.css("i").first, let className = icon.className else { return } for status in Status.allCases where className.contains("component-\(status.rawValue)") { let componentName = tds[0].css("a").first?.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "" // Geographic region names (e.g. "North America") are replaced with their parent tab name (e.g. "Platform") let pid = row["data-pid"] ?? "" let isRegion = Self.geographicRegionNames.contains(componentName) let name = isRegion ? (tabNames[pid] ?? componentName) : componentName componentStatuses.append((name: name, status: status)) break } } guard !componentStatuses.isEmpty else { throw StatusUpdateError.decodingError(nil) } let worstStatus = componentStatuses.max(by: { $0.status.serviceStatus < $1.status.serviceStatus })!.status let affected = componentStatuses .filter { $0.status != .available } .map { $0.name } .filter { !$0.isEmpty } var seen = Set() let uniqueAffected = affected.filter { seen.insert($0).inserted } let message = uniqueAffected.isEmpty ? worstStatus.displayText : uniqueAffected.joined(separator: ", ") statusDescription = ServiceStatusDescription(status: worstStatus.serviceStatus, message: message) } } ================================================ FILE: stts/Services/Firebase.swift ================================================ // // FirebaseAll.swift // stts // import Foundation class Firebase: FirebaseService, ServiceCategory { let categoryName = "Firebase" let subServiceSuperclass: AnyObject.Type = BaseFirebaseService.self let name = "Firebase (All)" } ================================================ FILE: stts/Services/Generated/AWSServices.swift ================================================ // This file is generated by generate_aws_services.swift and should not be modified manually. // swiftlint:disable superfluous_disable_command type_name import Foundation final class AWSRegions: AWSAllService, ServiceCategory { let categoryName = "Amazon Web Services (by region)" let subServiceSuperclass: AnyObject.Type = BaseAWSRegionService.self let name = "AWS Regions (All)" } final class AWSServices: AWSAllService, ServiceCategory { let categoryName = "Amazon Web Services" let subServiceSuperclass: AnyObject.Type = BaseAWSNamedService.self let name = "AWS (All)" } final class AWSBahrain: AWSRegionService, SubService { let id = "me-south-1" let name = "AWS (Bahrain)" } final class AWSCalgary: AWSRegionService, SubService { let id = "ca-west-1" let name = "AWS (Calgary)" } final class AWSCanadaCentral: AWSRegionService, SubService { let id = "ca-central-1" let name = "AWS (Canada-Central)" } final class AWSCapeTown: AWSRegionService, SubService { let id = "af-south-1" let name = "AWS (Cape Town)" } final class AWSFrankfurt: AWSRegionService, SubService { let id = "eu-central-1" let name = "AWS (Frankfurt)" } final class AWSHongKong: AWSRegionService, SubService { let id = "ap-east-1" let name = "AWS (Hong Kong)" } final class AWSHyderabad: AWSRegionService, SubService { let id = "ap-south-2" let name = "AWS (Hyderabad)" } final class AWSIreland: AWSRegionService, SubService { let id = "eu-west-1" let name = "AWS (Ireland)" } final class AWSJakarta: AWSRegionService, SubService { let id = "ap-southeast-3" let name = "AWS (Jakarta)" } final class AWSLondon: AWSRegionService, SubService { let id = "eu-west-2" let name = "AWS (London)" } final class AWSMalaysia: AWSRegionService, SubService { let id = "ap-southeast-5" let name = "AWS (Malaysia)" } final class AWSMelbourne: AWSRegionService, SubService { let id = "ap-southeast-4" let name = "AWS (Melbourne)" } final class AWSMexicoCentral: AWSRegionService, SubService { let id = "mx-central-1" let name = "AWS (Mexico-Central)" } final class AWSMilan: AWSRegionService, SubService { let id = "eu-south-1" let name = "AWS (Milan)" } final class AWSMumbai: AWSRegionService, SubService { let id = "ap-south-1" let name = "AWS (Mumbai)" } final class AWSNCalifornia: AWSRegionService, SubService { let id = "us-west-1" let name = "AWS (N. California)" } final class AWSNVirginia: AWSRegionService, SubService { let id = "us-east-1" let name = "AWS (N. Virginia)" } final class AWSNewZealand: AWSRegionService, SubService { let id = "ap-southeast-6" let name = "AWS (New Zealand)" } final class AWSOhio: AWSRegionService, SubService { let id = "us-east-2" let name = "AWS (Ohio)" } final class AWSOregon: AWSRegionService, SubService { let id = "us-west-2" let name = "AWS (Oregon)" } final class AWSOsaka: AWSRegionService, SubService { let id = "ap-northeast-3" let name = "AWS (Osaka)" } final class AWSParis: AWSRegionService, SubService { let id = "eu-west-3" let name = "AWS (Paris)" } final class AWSSaoPaulo: AWSRegionService, SubService { let id = "sa-east-1" let name = "AWS (Sao Paulo)" } final class AWSSeoul: AWSRegionService, SubService { let id = "ap-northeast-2" let name = "AWS (Seoul)" } final class AWSSingapore: AWSRegionService, SubService { let id = "ap-southeast-1" let name = "AWS (Singapore)" } final class AWSSpain: AWSRegionService, SubService { let id = "eu-south-2" let name = "AWS (Spain)" } final class AWSStockholm: AWSRegionService, SubService { let id = "eu-north-1" let name = "AWS (Stockholm)" } final class AWSSydney: AWSRegionService, SubService { let id = "ap-southeast-2" let name = "AWS (Sydney)" } final class AWSTaipei: AWSRegionService, SubService { let id = "ap-east-2" let name = "AWS (Taipei)" } final class AWSTelAviv: AWSRegionService, SubService { let id = "il-central-1" let name = "AWS (Tel Aviv)" } final class AWSThailand: AWSRegionService, SubService { let id = "ap-southeast-7" let name = "AWS (Thailand)" } final class AWSTokyo: AWSRegionService, SubService { let id = "ap-northeast-1" let name = "AWS (Tokyo)" } final class AWSUAE: AWSRegionService, SubService { let id = "me-central-1" let name = "AWS (UAE)" } final class AWSUSEast: AWSRegionService, SubService { let id = "us-gov-east-1" let name = "AWS (US-East)" } final class AWSUSWest: AWSRegionService, SubService { let id = "us-gov-west-1" let name = "AWS (US-West)" } final class AWSZurich: AWSRegionService, SubService { let id = "eu-central-2" let name = "AWS (Zurich)" } final class AWSAccountManagement: AWSNamedService, SubService { let name = "AWS Account Management" let ids = Set([ "account" ]) } final class AWSActivateConsole: AWSNamedService, SubService { let name = "AWS Activate Console" let ids = Set([ "activateconsole-us-west-2" ]) } final class AWSAmplify: AWSNamedService, SubService { let name = "AWS Amplify" let ids = Set([ "amplify-ap-east-1", "amplify-ap-northeast-1", "amplify-ap-northeast-2", "amplify-ap-northeast-3", "amplify-ap-south-1", "amplify-ap-southeast-1", "amplify-ap-southeast-2", "amplify-ca-central-1", "amplify-eu-central-1", "amplify-eu-north-1", "amplify-eu-south-1", "amplify-eu-west-1", "amplify-eu-west-2", "amplify-eu-west-3", "amplify-me-south-1", "amplify-sa-east-1", "amplify-us-east-1", "amplify-us-east-2", "amplify-us-west-1", "amplify-us-west-2" ]) } final class AWSAmplifyAdmin: AWSNamedService, SubService { let name = "AWS Amplify Admin" let ids = Set([ "amplifyadmin-ap-northeast-1", "amplifyadmin-ap-northeast-2", "amplifyadmin-ap-northeast-3", "amplifyadmin-ap-south-1", "amplifyadmin-ap-southeast-1", "amplifyadmin-ap-southeast-2", "amplifyadmin-ca-central-1", "amplifyadmin-eu-central-1", "amplifyadmin-eu-north-1", "amplifyadmin-eu-south-1", "amplifyadmin-eu-west-1", "amplifyadmin-eu-west-2", "amplifyadmin-eu-west-3", "amplifyadmin-me-south-1", "amplifyadmin-sa-east-1", "amplifyadmin-us-east-1", "amplifyadmin-us-east-2", "amplifyadmin-us-west-1", "amplifyadmin-us-west-2" ]) } final class AWSAppMesh: AWSNamedService, SubService { let name = "AWS App Mesh" let ids = Set([ "appmesh-af-south-1", "appmesh-ap-east-1", "appmesh-ap-northeast-1", "appmesh-ap-northeast-2", "appmesh-ap-northeast-3", "appmesh-ap-south-1", "appmesh-ap-southeast-1", "appmesh-ap-southeast-2", "appmesh-ap-southeast-3", "appmesh-ca-central-1", "appmesh-eu-central-1", "appmesh-eu-central-2", "appmesh-eu-north-1", "appmesh-eu-south-1", "appmesh-eu-south-2", "appmesh-eu-west-1", "appmesh-eu-west-2", "appmesh-eu-west-3", "appmesh-il-central-1", "appmesh-me-south-1", "appmesh-sa-east-1", "appmesh-us-east-1", "appmesh-us-east-2", "appmesh-us-west-1", "appmesh-us-west-2" ]) } final class AWSAppRunner: AWSNamedService, SubService { let name = "AWS App Runner" let ids = Set([ "apprunner-ap-northeast-1", "apprunner-ap-south-1", "apprunner-ap-southeast-1", "apprunner-ap-southeast-2", "apprunner-eu-central-1", "apprunner-eu-west-1", "apprunner-eu-west-2", "apprunner-eu-west-3", "apprunner-us-east-1", "apprunner-us-east-2", "apprunner-us-west-2" ]) } final class AWSAppStudio: AWSNamedService, SubService { let name = "AWS App Studio" let ids = Set([ "appstudio-eu-west-1", "appstudio-us-west-2" ]) } final class AWSAppConfig: AWSNamedService, SubService { let name = "AWS AppConfig" let ids = Set([ "appconfig-af-south-1", "appconfig-ap-east-1", "appconfig-ap-east-2", "appconfig-ap-northeast-1", "appconfig-ap-northeast-2", "appconfig-ap-northeast-3", "appconfig-ap-south-1", "appconfig-ap-south-2", "appconfig-ap-southeast-1", "appconfig-ap-southeast-2", "appconfig-ap-southeast-3", "appconfig-ap-southeast-4", "appconfig-ap-southeast-5", "appconfig-ap-southeast-6", "appconfig-ap-southeast-7", "appconfig-ca-central-1", "appconfig-ca-west-1", "appconfig-eu-central-1", "appconfig-eu-central-2", "appconfig-eu-north-1", "appconfig-eu-south-1", "appconfig-eu-south-2", "appconfig-eu-west-1", "appconfig-eu-west-2", "appconfig-eu-west-3", "appconfig-il-central-1", "appconfig-me-central-1", "appconfig-me-south-1", "appconfig-mx-central-1", "appconfig-sa-east-1", "appconfig-us-east-1", "appconfig-us-east-2", "appconfig-us-gov-east-1", "appconfig-us-gov-west-1", "appconfig-us-west-1", "appconfig-us-west-2" ]) } final class AWSAppFabric: AWSNamedService, SubService { let name = "AWS AppFabric" let ids = Set([ "appfabric-ap-northeast-1", "appfabric-eu-west-1", "appfabric-us-east-1" ]) } final class AWSAppSync: AWSNamedService, SubService { let name = "AWS AppSync" let ids = Set([ "appsync-af-south-1", "appsync-ap-east-1", "appsync-ap-northeast-1", "appsync-ap-northeast-2", "appsync-ap-northeast-3", "appsync-ap-south-1", "appsync-ap-south-2", "appsync-ap-southeast-1", "appsync-ap-southeast-2", "appsync-ap-southeast-3", "appsync-ap-southeast-4", "appsync-ap-southeast-5", "appsync-ap-southeast-7", "appsync-ca-central-1", "appsync-ca-west-1", "appsync-eu-central-1", "appsync-eu-central-2", "appsync-eu-north-1", "appsync-eu-south-1", "appsync-eu-south-2", "appsync-eu-west-1", "appsync-eu-west-2", "appsync-eu-west-3", "appsync-il-central-1", "appsync-me-central-1", "appsync-me-south-1", "appsync-sa-east-1", "appsync-us-east-1", "appsync-us-east-2", "appsync-us-west-1", "appsync-us-west-2" ]) } final class AWSApplicationDiscoveryService: AWSNamedService, SubService { let name = "AWS Application Discovery Service" let ids = Set([ "applicationdiscoveryservice-ap-northeast-1", "applicationdiscoveryservice-ap-southeast-2", "applicationdiscoveryservice-eu-central-1", "applicationdiscoveryservice-eu-west-1", "applicationdiscoveryservice-eu-west-2", "applicationdiscoveryservice-us-east-1", "applicationdiscoveryservice-us-west-2" ]) } final class AWSApplicationMigrationService: AWSNamedService, SubService { let name = "AWS Application Migration Service" let ids = Set([ "mgn-af-south-1", "mgn-ap-east-1", "mgn-ap-northeast-1", "mgn-ap-northeast-2", "mgn-ap-northeast-3", "mgn-ap-south-1", "mgn-ap-south-2", "mgn-ap-southeast-1", "mgn-ap-southeast-2", "mgn-ap-southeast-3", "mgn-ap-southeast-4", "mgn-ap-southeast-5", "mgn-ap-southeast-7", "mgn-ca-central-1", "mgn-eu-central-1", "mgn-eu-central-2", "mgn-eu-north-1", "mgn-eu-south-1", "mgn-eu-south-2", "mgn-eu-west-1", "mgn-eu-west-2", "mgn-eu-west-3", "mgn-il-central-1", "mgn-me-central-1", "mgn-me-south-1", "mgn-sa-east-1", "mgn-us-east-1", "mgn-us-east-2", "mgn-us-gov-east-1", "mgn-us-gov-west-1", "mgn-us-west-1", "mgn-us-west-2" ]) } final class AWSAuditManager: AWSNamedService, SubService { let name = "AWS Audit Manager" let ids = Set([ "auditmanager-ap-northeast-1", "auditmanager-ap-south-1", "auditmanager-ap-southeast-1", "auditmanager-ap-southeast-2", "auditmanager-ca-central-1", "auditmanager-eu-central-1", "auditmanager-eu-west-1", "auditmanager-eu-west-2", "auditmanager-us-east-1", "auditmanager-us-east-2", "auditmanager-us-west-1", "auditmanager-us-west-2" ]) } final class AWSAutoScaling: AWSNamedService, SubService { let name = "AWS Auto Scaling" let ids = Set([ "autoscaling-af-south-1", "autoscaling-ap-east-1", "autoscaling-ap-east-2", "autoscaling-ap-northeast-1", "autoscaling-ap-northeast-2", "autoscaling-ap-northeast-3", "autoscaling-ap-south-1", "autoscaling-ap-south-2", "autoscaling-ap-southeast-1", "autoscaling-ap-southeast-2", "autoscaling-ap-southeast-3", "autoscaling-ap-southeast-4", "autoscaling-ap-southeast-5", "autoscaling-ap-southeast-6", "autoscaling-ap-southeast-7", "autoscaling-ca-central-1", "autoscaling-ca-west-1", "autoscaling-eu-central-1", "autoscaling-eu-central-2", "autoscaling-eu-north-1", "autoscaling-eu-south-1", "autoscaling-eu-south-2", "autoscaling-eu-west-1", "autoscaling-eu-west-2", "autoscaling-eu-west-3", "autoscaling-il-central-1", "autoscaling-me-central-1", "autoscaling-me-south-1", "autoscaling-mx-central-1", "autoscaling-sa-east-1", "autoscaling-us-east-1", "autoscaling-us-east-2", "autoscaling-us-gov-east-1", "autoscaling-us-gov-west-1", "autoscaling-us-west-1", "autoscaling-us-west-2" ]) } final class AWSB2BDataInterchange: AWSNamedService, SubService { let name = "AWS B2B Data Interchange" let ids = Set([ "b2bi-ap-south-2", "b2bi-ap-southeast-2", "b2bi-ca-central-1", "b2bi-eu-central-1", "b2bi-eu-west-1", "b2bi-eu-west-3", "b2bi-us-east-1", "b2bi-us-east-2", "b2bi-us-west-2" ]) } final class AWSBackup: AWSNamedService, SubService { let name = "AWS Backup" let ids = Set([ "backup-af-south-1", "backup-ap-east-1", "backup-ap-east-2", "backup-ap-northeast-1", "backup-ap-northeast-2", "backup-ap-northeast-3", "backup-ap-south-1", "backup-ap-south-2", "backup-ap-southeast-1", "backup-ap-southeast-2", "backup-ap-southeast-3", "backup-ap-southeast-4", "backup-ap-southeast-5", "backup-ap-southeast-6", "backup-ap-southeast-7", "backup-ca-central-1", "backup-ca-west-1", "backup-eu-central-1", "backup-eu-central-2", "backup-eu-north-1", "backup-eu-south-1", "backup-eu-south-2", "backup-eu-west-1", "backup-eu-west-2", "backup-eu-west-3", "backup-il-central-1", "backup-me-central-1", "backup-me-south-1", "backup-mx-central-1", "backup-sa-east-1", "backup-us-east-1", "backup-us-east-2", "backup-us-gov-east-1", "backup-us-gov-west-1", "backup-us-west-1", "backup-us-west-2" ]) } final class AWSBatch: AWSNamedService, SubService { let name = "AWS Batch" let ids = Set([ "batch-af-south-1", "batch-ap-east-1", "batch-ap-east-2", "batch-ap-northeast-1", "batch-ap-northeast-2", "batch-ap-northeast-3", "batch-ap-south-1", "batch-ap-south-2", "batch-ap-southeast-1", "batch-ap-southeast-2", "batch-ap-southeast-3", "batch-ap-southeast-4", "batch-ap-southeast-5", "batch-ap-southeast-6", "batch-ap-southeast-7", "batch-ca-central-1", "batch-ca-west-1", "batch-eu-central-1", "batch-eu-central-2", "batch-eu-north-1", "batch-eu-south-1", "batch-eu-south-2", "batch-eu-west-1", "batch-eu-west-2", "batch-eu-west-3", "batch-il-central-1", "batch-me-central-1", "batch-me-south-1", "batch-mx-central-1", "batch-sa-east-1", "batch-us-east-1", "batch-us-east-2", "batch-us-gov-east-1", "batch-us-gov-west-1", "batch-us-west-1", "batch-us-west-2" ]) } final class AWSBedrockAgentCore: AWSNamedService, SubService { let name = "AWS Bedrock AgentCore" let ids = Set([ "bedrock-agentcore-ap-northeast-1", "bedrock-agentcore-ap-northeast-2", "bedrock-agentcore-ap-south-1", "bedrock-agentcore-ap-southeast-1", "bedrock-agentcore-ap-southeast-2", "bedrock-agentcore-ca-central-1", "bedrock-agentcore-eu-central-1", "bedrock-agentcore-eu-north-1", "bedrock-agentcore-eu-west-1", "bedrock-agentcore-eu-west-2", "bedrock-agentcore-eu-west-3", "bedrock-agentcore-us-east-1", "bedrock-agentcore-us-east-2", "bedrock-agentcore-us-west-2" ]) } final class AWSBillingConsole: AWSNamedService, SubService { let name = "AWS Billing Console" let ids = Set([ "billingconsole" ]) } final class AWSCertificateManager: AWSNamedService, SubService { let name = "AWS Certificate Manager" let ids = Set([ "certificatemanager-af-south-1", "certificatemanager-ap-east-1", "certificatemanager-ap-east-2", "certificatemanager-ap-northeast-1", "certificatemanager-ap-northeast-2", "certificatemanager-ap-northeast-3", "certificatemanager-ap-south-1", "certificatemanager-ap-south-2", "certificatemanager-ap-southeast-1", "certificatemanager-ap-southeast-2", "certificatemanager-ap-southeast-3", "certificatemanager-ap-southeast-4", "certificatemanager-ap-southeast-5", "certificatemanager-ap-southeast-6", "certificatemanager-ap-southeast-7", "certificatemanager-ca-central-1", "certificatemanager-ca-west-1", "certificatemanager-eu-central-1", "certificatemanager-eu-central-2", "certificatemanager-eu-north-1", "certificatemanager-eu-south-1", "certificatemanager-eu-south-2", "certificatemanager-eu-west-1", "certificatemanager-eu-west-2", "certificatemanager-eu-west-3", "certificatemanager-il-central-1", "certificatemanager-me-central-1", "certificatemanager-me-south-1", "certificatemanager-mx-central-1", "certificatemanager-sa-east-1", "certificatemanager-us-east-1", "certificatemanager-us-east-2", "certificatemanager-us-gov-east-1", "certificatemanager-us-gov-west-1", "certificatemanager-us-west-1", "certificatemanager-us-west-2" ]) } final class AWSChatbot: AWSNamedService, SubService { let name = "AWS Chatbot" let ids = Set([ "chatbot" ]) } final class AWSCleanRooms: AWSNamedService, SubService { let name = "AWS Clean Rooms" let ids = Set([ "cleanrooms-ap-northeast-1", "cleanrooms-ap-northeast-2", "cleanrooms-ap-southeast-1", "cleanrooms-ap-southeast-2", "cleanrooms-eu-central-1", "cleanrooms-eu-north-1", "cleanrooms-eu-west-1", "cleanrooms-eu-west-2", "cleanrooms-us-east-1", "cleanrooms-us-east-2", "cleanrooms-us-west-2" ]) } final class AWSClientVPN: AWSNamedService, SubService { let name = "AWS Client VPN" let ids = Set([ "clientvpn-af-south-1", "clientvpn-ap-east-1", "clientvpn-ap-northeast-1", "clientvpn-ap-northeast-2", "clientvpn-ap-northeast-3", "clientvpn-ap-south-1", "clientvpn-ap-south-2", "clientvpn-ap-southeast-1", "clientvpn-ap-southeast-2", "clientvpn-ap-southeast-3", "clientvpn-ap-southeast-4", "clientvpn-ap-southeast-5", "clientvpn-ap-southeast-7", "clientvpn-ca-central-1", "clientvpn-eu-central-1", "clientvpn-eu-central-2", "clientvpn-eu-north-1", "clientvpn-eu-south-1", "clientvpn-eu-south-2", "clientvpn-eu-west-1", "clientvpn-eu-west-2", "clientvpn-eu-west-3", "clientvpn-il-central-1", "clientvpn-me-central-1", "clientvpn-me-south-1", "clientvpn-sa-east-1", "clientvpn-us-east-1", "clientvpn-us-east-2", "clientvpn-us-gov-east-1", "clientvpn-us-gov-west-1", "clientvpn-us-west-1", "clientvpn-us-west-2" ]) } final class AWSCloudMap: AWSNamedService, SubService { let name = "AWS Cloud Map" let ids = Set([ "servicediscovery-af-south-1", "servicediscovery-ap-east-1", "servicediscovery-ap-east-2", "servicediscovery-ap-northeast-1", "servicediscovery-ap-northeast-2", "servicediscovery-ap-northeast-3", "servicediscovery-ap-south-1", "servicediscovery-ap-south-2", "servicediscovery-ap-southeast-1", "servicediscovery-ap-southeast-2", "servicediscovery-ap-southeast-3", "servicediscovery-ap-southeast-4", "servicediscovery-ap-southeast-5", "servicediscovery-ap-southeast-6", "servicediscovery-ap-southeast-7", "servicediscovery-ca-central-1", "servicediscovery-ca-west-1", "servicediscovery-eu-central-1", "servicediscovery-eu-central-2", "servicediscovery-eu-north-1", "servicediscovery-eu-south-1", "servicediscovery-eu-south-2", "servicediscovery-eu-west-1", "servicediscovery-eu-west-2", "servicediscovery-eu-west-3", "servicediscovery-il-central-1", "servicediscovery-me-central-1", "servicediscovery-me-south-1", "servicediscovery-mx-central-1", "servicediscovery-sa-east-1", "servicediscovery-us-east-1", "servicediscovery-us-east-2", "servicediscovery-us-gov-east-1", "servicediscovery-us-gov-west-1", "servicediscovery-us-west-1", "servicediscovery-us-west-2" ]) } final class AWSCloudWAN: AWSNamedService, SubService { let name = "AWS Cloud WAN" let ids = Set([ "cloudwan", "cloudwan-us-gov-east-1", "cloudwan-us-gov-west-1" ]) } final class AWSCloud9: AWSNamedService, SubService { let name = "AWS Cloud9" let ids = Set([ "cloud9-af-south-1", "cloud9-ap-east-1", "cloud9-ap-northeast-1", "cloud9-ap-northeast-2", "cloud9-ap-northeast-3", "cloud9-ap-south-1", "cloud9-ap-southeast-1", "cloud9-ap-southeast-2", "cloud9-ca-central-1", "cloud9-eu-central-1", "cloud9-eu-north-1", "cloud9-eu-south-1", "cloud9-eu-west-1", "cloud9-eu-west-2", "cloud9-eu-west-3", "cloud9-il-central-1", "cloud9-me-south-1", "cloud9-sa-east-1", "cloud9-us-east-1", "cloud9-us-east-2", "cloud9-us-west-1", "cloud9-us-west-2" ]) } final class AWSCloudFormation: AWSNamedService, SubService { let name = "AWS CloudFormation" let ids = Set([ "cloudformation-af-south-1", "cloudformation-ap-east-1", "cloudformation-ap-east-2", "cloudformation-ap-northeast-1", "cloudformation-ap-northeast-2", "cloudformation-ap-northeast-3", "cloudformation-ap-south-1", "cloudformation-ap-south-2", "cloudformation-ap-southeast-1", "cloudformation-ap-southeast-2", "cloudformation-ap-southeast-3", "cloudformation-ap-southeast-4", "cloudformation-ap-southeast-5", "cloudformation-ap-southeast-6", "cloudformation-ap-southeast-7", "cloudformation-ca-central-1", "cloudformation-ca-west-1", "cloudformation-eu-central-1", "cloudformation-eu-central-2", "cloudformation-eu-north-1", "cloudformation-eu-south-1", "cloudformation-eu-south-2", "cloudformation-eu-west-1", "cloudformation-eu-west-2", "cloudformation-eu-west-3", "cloudformation-il-central-1", "cloudformation-me-central-1", "cloudformation-me-south-1", "cloudformation-mx-central-1", "cloudformation-sa-east-1", "cloudformation-us-east-1", "cloudformation-us-east-2", "cloudformation-us-gov-east-1", "cloudformation-us-gov-west-1", "cloudformation-us-west-1", "cloudformation-us-west-2" ]) } final class AWSCloudHSM: AWSNamedService, SubService { let name = "AWS CloudHSM" let ids = Set([ "cloudhsm-af-south-1", "cloudhsm-ap-east-1", "cloudhsm-ap-northeast-1", "cloudhsm-ap-northeast-2", "cloudhsm-ap-northeast-3", "cloudhsm-ap-south-1", "cloudhsm-ap-south-2", "cloudhsm-ap-southeast-1", "cloudhsm-ap-southeast-2", "cloudhsm-ap-southeast-3", "cloudhsm-ap-southeast-5", "cloudhsm-ca-central-1", "cloudhsm-ca-west-1", "cloudhsm-eu-central-1", "cloudhsm-eu-central-2", "cloudhsm-eu-north-1", "cloudhsm-eu-south-1", "cloudhsm-eu-south-2", "cloudhsm-eu-west-1", "cloudhsm-eu-west-2", "cloudhsm-eu-west-3", "cloudhsm-il-central-1", "cloudhsm-me-central-1", "cloudhsm-me-south-1", "cloudhsm-mx-central-1", "cloudhsm-sa-east-1", "cloudhsm-us-east-1", "cloudhsm-us-east-2", "cloudhsm-us-gov-east-1", "cloudhsm-us-gov-west-1", "cloudhsm-us-west-1", "cloudhsm-us-west-2" ]) } final class AWSCloudShell: AWSNamedService, SubService { let name = "AWS CloudShell" let ids = Set([ "cloudshell-af-south-1", "cloudshell-ap-east-1", "cloudshell-ap-northeast-1", "cloudshell-ap-northeast-2", "cloudshell-ap-northeast-3", "cloudshell-ap-south-1", "cloudshell-ap-south-2", "cloudshell-ap-southeast-1", "cloudshell-ap-southeast-2", "cloudshell-ap-southeast-3", "cloudshell-ap-southeast-4", "cloudshell-ca-central-1", "cloudshell-ca-west-1", "cloudshell-eu-central-1", "cloudshell-eu-north-1", "cloudshell-eu-south-1", "cloudshell-eu-south-2", "cloudshell-eu-west-1", "cloudshell-eu-west-2", "cloudshell-eu-west-3", "cloudshell-il-central-1", "cloudshell-me-central-1", "cloudshell-me-south-1", "cloudshell-sa-east-1", "cloudshell-us-east-1", "cloudshell-us-east-2", "cloudshell-us-gov-east-1", "cloudshell-us-gov-west-1", "cloudshell-us-west-1", "cloudshell-us-west-2" ]) } final class AWSCloudTrail: AWSNamedService, SubService { let name = "AWS CloudTrail" let ids = Set([ "cloudtrail-af-south-1", "cloudtrail-ap-east-1", "cloudtrail-ap-east-2", "cloudtrail-ap-northeast-1", "cloudtrail-ap-northeast-2", "cloudtrail-ap-northeast-3", "cloudtrail-ap-south-1", "cloudtrail-ap-south-2", "cloudtrail-ap-southeast-1", "cloudtrail-ap-southeast-2", "cloudtrail-ap-southeast-3", "cloudtrail-ap-southeast-4", "cloudtrail-ap-southeast-5", "cloudtrail-ap-southeast-6", "cloudtrail-ap-southeast-7", "cloudtrail-ca-central-1", "cloudtrail-ca-west-1", "cloudtrail-eu-central-1", "cloudtrail-eu-central-2", "cloudtrail-eu-north-1", "cloudtrail-eu-south-1", "cloudtrail-eu-south-2", "cloudtrail-eu-west-1", "cloudtrail-eu-west-2", "cloudtrail-eu-west-3", "cloudtrail-il-central-1", "cloudtrail-me-central-1", "cloudtrail-me-south-1", "cloudtrail-mx-central-1", "cloudtrail-sa-east-1", "cloudtrail-us-east-1", "cloudtrail-us-east-2", "cloudtrail-us-gov-east-1", "cloudtrail-us-gov-west-1", "cloudtrail-us-west-1", "cloudtrail-us-west-2" ]) } final class AWSCodeArtifact: AWSNamedService, SubService { let name = "AWS CodeArtifact" let ids = Set([ "codeartifact-ap-northeast-1", "codeartifact-ap-south-1", "codeartifact-ap-southeast-1", "codeartifact-ap-southeast-2", "codeartifact-eu-central-1", "codeartifact-eu-north-1", "codeartifact-eu-south-1", "codeartifact-eu-west-1", "codeartifact-eu-west-2", "codeartifact-eu-west-3", "codeartifact-us-east-1", "codeartifact-us-east-2", "codeartifact-us-west-2" ]) } final class AWSCodeBuild: AWSNamedService, SubService { let name = "AWS CodeBuild" let ids = Set([ "codebuild-af-south-1", "codebuild-ap-east-1", "codebuild-ap-northeast-1", "codebuild-ap-northeast-2", "codebuild-ap-northeast-3", "codebuild-ap-south-1", "codebuild-ap-south-2", "codebuild-ap-southeast-1", "codebuild-ap-southeast-2", "codebuild-ap-southeast-3", "codebuild-ap-southeast-4", "codebuild-ca-central-1", "codebuild-eu-central-1", "codebuild-eu-central-2", "codebuild-eu-north-1", "codebuild-eu-south-1", "codebuild-eu-south-2", "codebuild-eu-west-1", "codebuild-eu-west-2", "codebuild-eu-west-3", "codebuild-il-central-1", "codebuild-me-central-1", "codebuild-me-south-1", "codebuild-sa-east-1", "codebuild-us-east-1", "codebuild-us-east-2", "codebuild-us-gov-east-1", "codebuild-us-gov-west-1", "codebuild-us-west-1", "codebuild-us-west-2" ]) } final class AWSCodeCommit: AWSNamedService, SubService { let name = "AWS CodeCommit" let ids = Set([ "codecommit-af-south-1", "codecommit-ap-east-1", "codecommit-ap-northeast-1", "codecommit-ap-northeast-2", "codecommit-ap-northeast-3", "codecommit-ap-south-1", "codecommit-ap-south-2", "codecommit-ap-southeast-1", "codecommit-ap-southeast-2", "codecommit-ap-southeast-3", "codecommit-ca-central-1", "codecommit-eu-central-1", "codecommit-eu-north-1", "codecommit-eu-south-1", "codecommit-eu-west-1", "codecommit-eu-west-2", "codecommit-eu-west-3", "codecommit-il-central-1", "codecommit-me-central-1", "codecommit-me-south-1", "codecommit-sa-east-1", "codecommit-us-east-1", "codecommit-us-east-2", "codecommit-us-gov-east-1", "codecommit-us-gov-west-1", "codecommit-us-west-1", "codecommit-us-west-2" ]) } final class AWSCodeDeploy: AWSNamedService, SubService { let name = "AWS CodeDeploy" let ids = Set([ "codedeploy-af-south-1", "codedeploy-ap-east-1", "codedeploy-ap-east-2", "codedeploy-ap-northeast-1", "codedeploy-ap-northeast-2", "codedeploy-ap-northeast-3", "codedeploy-ap-south-1", "codedeploy-ap-south-2", "codedeploy-ap-southeast-1", "codedeploy-ap-southeast-2", "codedeploy-ap-southeast-3", "codedeploy-ap-southeast-4", "codedeploy-ca-central-1", "codedeploy-ca-west-1", "codedeploy-eu-central-1", "codedeploy-eu-central-2", "codedeploy-eu-north-1", "codedeploy-eu-south-1", "codedeploy-eu-south-2", "codedeploy-eu-west-1", "codedeploy-eu-west-2", "codedeploy-eu-west-3", "codedeploy-il-central-1", "codedeploy-me-central-1", "codedeploy-me-south-1", "codedeploy-sa-east-1", "codedeploy-us-east-1", "codedeploy-us-east-2", "codedeploy-us-gov-east-1", "codedeploy-us-gov-west-1", "codedeploy-us-west-1", "codedeploy-us-west-2" ]) } final class AWSCodePipeline: AWSNamedService, SubService { let name = "AWS CodePipeline" let ids = Set([ "codepipeline-af-south-1", "codepipeline-ap-east-1", "codepipeline-ap-northeast-1", "codepipeline-ap-northeast-2", "codepipeline-ap-northeast-3", "codepipeline-ap-south-1", "codepipeline-ap-south-2", "codepipeline-ap-southeast-1", "codepipeline-ap-southeast-2", "codepipeline-ap-southeast-3", "codepipeline-ap-southeast-4", "codepipeline-ap-southeast-5", "codepipeline-ca-central-1", "codepipeline-eu-central-1", "codepipeline-eu-central-2", "codepipeline-eu-north-1", "codepipeline-eu-south-1", "codepipeline-eu-south-2", "codepipeline-eu-west-1", "codepipeline-eu-west-2", "codepipeline-eu-west-3", "codepipeline-il-central-1", "codepipeline-me-central-1", "codepipeline-me-south-1", "codepipeline-sa-east-1", "codepipeline-us-east-1", "codepipeline-us-east-2", "codepipeline-us-gov-east-1", "codepipeline-us-gov-west-1", "codepipeline-us-west-1", "codepipeline-us-west-2" ]) } final class AWSComputeOptimizer: AWSNamedService, SubService { let name = "AWS Compute Optimizer" let ids = Set([ "computeoptimizer-af-south-1", "computeoptimizer-ap-east-1", "computeoptimizer-ap-northeast-1", "computeoptimizer-ap-northeast-2", "computeoptimizer-ap-northeast-3", "computeoptimizer-ap-south-1", "computeoptimizer-ap-south-2", "computeoptimizer-ap-southeast-1", "computeoptimizer-ap-southeast-2", "computeoptimizer-ap-southeast-3", "computeoptimizer-ap-southeast-4", "computeoptimizer-ca-central-1", "computeoptimizer-eu-central-1", "computeoptimizer-eu-central-2", "computeoptimizer-eu-north-1", "computeoptimizer-eu-south-1", "computeoptimizer-eu-south-2", "computeoptimizer-eu-west-1", "computeoptimizer-eu-west-2", "computeoptimizer-eu-west-3", "computeoptimizer-il-central-1", "computeoptimizer-me-central-1", "computeoptimizer-me-south-1", "computeoptimizer-sa-east-1", "computeoptimizer-us-east-1", "computeoptimizer-us-east-2", "computeoptimizer-us-gov-east-1", "computeoptimizer-us-gov-west-1", "computeoptimizer-us-west-1", "computeoptimizer-us-west-2" ]) } final class AWSConfig: AWSNamedService, SubService { let name = "AWS Config" let ids = Set([ "config-af-south-1", "config-ap-east-1", "config-ap-east-2", "config-ap-northeast-1", "config-ap-northeast-2", "config-ap-northeast-3", "config-ap-south-1", "config-ap-south-2", "config-ap-southeast-1", "config-ap-southeast-2", "config-ap-southeast-3", "config-ap-southeast-4", "config-ap-southeast-5", "config-ap-southeast-6", "config-ap-southeast-7", "config-ca-central-1", "config-ca-west-1", "config-eu-central-1", "config-eu-central-2", "config-eu-north-1", "config-eu-south-1", "config-eu-south-2", "config-eu-west-1", "config-eu-west-2", "config-eu-west-3", "config-il-central-1", "config-me-central-1", "config-me-south-1", "config-mx-central-1", "config-sa-east-1", "config-us-east-1", "config-us-east-2", "config-us-gov-east-1", "config-us-gov-west-1", "config-us-west-1", "config-us-west-2" ]) } final class AWSConsoleMobileApp: AWSNamedService, SubService { let name = "AWS Console Mobile App" let ids = Set([ "consolemobileapp-af-south-1", "consolemobileapp-ap-east-1", "consolemobileapp-ap-northeast-1", "consolemobileapp-ap-northeast-2", "consolemobileapp-ap-northeast-3", "consolemobileapp-ap-south-1", "consolemobileapp-ap-south-2", "consolemobileapp-ap-southeast-1", "consolemobileapp-ap-southeast-2", "consolemobileapp-ap-southeast-3", "consolemobileapp-ap-southeast-4", "consolemobileapp-ca-central-1", "consolemobileapp-ca-west-1", "consolemobileapp-eu-central-1", "consolemobileapp-eu-central-2", "consolemobileapp-eu-north-1", "consolemobileapp-eu-south-1", "consolemobileapp-eu-south-2", "consolemobileapp-eu-west-1", "consolemobileapp-eu-west-2", "consolemobileapp-eu-west-3", "consolemobileapp-il-central-1", "consolemobileapp-me-central-1", "consolemobileapp-me-south-1", "consolemobileapp-sa-east-1", "consolemobileapp-us-east-1", "consolemobileapp-us-east-2", "consolemobileapp-us-west-1", "consolemobileapp-us-west-2" ]) } final class AWSControlCatalog: AWSNamedService, SubService { let name = "AWS Control Catalog" let ids = Set([ "controlcatalog-af-south-1", "controlcatalog-ap-east-1", "controlcatalog-ap-east-2", "controlcatalog-ap-northeast-1", "controlcatalog-ap-northeast-2", "controlcatalog-ap-northeast-3", "controlcatalog-ap-south-1", "controlcatalog-ap-south-2", "controlcatalog-ap-southeast-1", "controlcatalog-ap-southeast-2", "controlcatalog-ap-southeast-3", "controlcatalog-ap-southeast-4", "controlcatalog-ap-southeast-5", "controlcatalog-ap-southeast-6", "controlcatalog-ap-southeast-7", "controlcatalog-ca-central-1", "controlcatalog-ca-west-1", "controlcatalog-eu-central-1", "controlcatalog-eu-central-2", "controlcatalog-eu-north-1", "controlcatalog-eu-south-1", "controlcatalog-eu-south-2", "controlcatalog-eu-west-1", "controlcatalog-eu-west-2", "controlcatalog-eu-west-3", "controlcatalog-il-central-1", "controlcatalog-me-central-1", "controlcatalog-me-south-1", "controlcatalog-mx-central-1", "controlcatalog-sa-east-1", "controlcatalog-us-east-1", "controlcatalog-us-east-2", "controlcatalog-us-gov-east-1", "controlcatalog-us-gov-west-1", "controlcatalog-us-west-1", "controlcatalog-us-west-2" ]) } final class AWSControlTower: AWSNamedService, SubService { let name = "AWS Control Tower" let ids = Set([ "controltower-af-south-1", "controltower-ap-east-1", "controltower-ap-east-2", "controltower-ap-northeast-1", "controltower-ap-northeast-2", "controltower-ap-northeast-3", "controltower-ap-south-1", "controltower-ap-south-2", "controltower-ap-southeast-1", "controltower-ap-southeast-2", "controltower-ap-southeast-3", "controltower-ap-southeast-4", "controltower-ap-southeast-5", "controltower-ap-southeast-6", "controltower-ap-southeast-7", "controltower-ca-central-1", "controltower-ca-west-1", "controltower-eu-central-1", "controltower-eu-central-2", "controltower-eu-north-1", "controltower-eu-south-1", "controltower-eu-south-2", "controltower-eu-west-1", "controltower-eu-west-2", "controltower-eu-west-3", "controltower-il-central-1", "controltower-me-central-1", "controltower-me-south-1", "controltower-mx-central-1", "controltower-sa-east-1", "controltower-us-east-1", "controltower-us-east-2", "controltower-us-gov-east-1", "controltower-us-gov-west-1", "controltower-us-west-1", "controltower-us-west-2" ]) } final class AWSDataExchange: AWSNamedService, SubService { let name = "AWS Data Exchange" let ids = Set([ "dataexchange-ap-northeast-1", "dataexchange-ap-northeast-2", "dataexchange-ap-southeast-1", "dataexchange-ap-southeast-2", "dataexchange-eu-central-1", "dataexchange-eu-west-1", "dataexchange-eu-west-2", "dataexchange-us-east-1", "dataexchange-us-east-2", "dataexchange-us-west-1", "dataexchange-us-west-2" ]) } final class AWSDataPipeline: AWSNamedService, SubService { let name = "AWS Data Pipeline" let ids = Set([ "datapipeline-ap-northeast-1", "datapipeline-ap-southeast-2", "datapipeline-eu-west-1", "datapipeline-us-east-1", "datapipeline-us-west-2" ]) } final class AWSDataSync: AWSNamedService, SubService { let name = "AWS DataSync" let ids = Set([ "datasync-af-south-1", "datasync-ap-east-1", "datasync-ap-east-2", "datasync-ap-northeast-1", "datasync-ap-northeast-2", "datasync-ap-northeast-3", "datasync-ap-south-1", "datasync-ap-south-2", "datasync-ap-southeast-1", "datasync-ap-southeast-2", "datasync-ap-southeast-3", "datasync-ap-southeast-4", "datasync-ap-southeast-5", "datasync-ap-southeast-6", "datasync-ap-southeast-7", "datasync-ca-central-1", "datasync-ca-west-1", "datasync-eu-central-1", "datasync-eu-central-2", "datasync-eu-north-1", "datasync-eu-south-1", "datasync-eu-south-2", "datasync-eu-west-1", "datasync-eu-west-2", "datasync-eu-west-3", "datasync-il-central-1", "datasync-me-central-1", "datasync-me-south-1", "datasync-mx-central-1", "datasync-sa-east-1", "datasync-us-east-1", "datasync-us-east-2", "datasync-us-gov-east-1", "datasync-us-gov-west-1", "datasync-us-west-1", "datasync-us-west-2" ]) } final class AWSDatabaseMigrationService: AWSNamedService, SubService { let name = "AWS Database Migration Service" let ids = Set([ "dms-af-south-1", "dms-ap-east-1", "dms-ap-east-2", "dms-ap-northeast-1", "dms-ap-northeast-2", "dms-ap-northeast-3", "dms-ap-south-1", "dms-ap-south-2", "dms-ap-southeast-1", "dms-ap-southeast-2", "dms-ap-southeast-3", "dms-ap-southeast-4", "dms-ap-southeast-5", "dms-ap-southeast-6", "dms-ap-southeast-7", "dms-ca-central-1", "dms-ca-west-1", "dms-eu-central-1", "dms-eu-central-2", "dms-eu-north-1", "dms-eu-south-1", "dms-eu-south-2", "dms-eu-west-1", "dms-eu-west-2", "dms-eu-west-3", "dms-il-central-1", "dms-me-central-1", "dms-me-south-1", "dms-mx-central-1", "dms-sa-east-1", "dms-us-east-1", "dms-us-east-2", "dms-us-gov-east-1", "dms-us-gov-west-1", "dms-us-west-1", "dms-us-west-2" ]) } final class AWSDeadlineCloud: AWSNamedService, SubService { let name = "AWS Deadline Cloud" let ids = Set([ "deadline-ap-northeast-1", "deadline-ap-northeast-2", "deadline-ap-southeast-1", "deadline-ap-southeast-2", "deadline-eu-central-1", "deadline-eu-west-1", "deadline-eu-west-2", "deadline-us-east-1", "deadline-us-east-2", "deadline-us-west-2" ]) } final class AWSDeepLens: AWSNamedService, SubService { let name = "AWS DeepLens" let ids = Set([ "deeplens-ap-northeast-1", "deeplens-eu-central-1", "deeplens-us-east-1" ]) } final class AWSDeepRacer: AWSNamedService, SubService { let name = "AWS DeepRacer" let ids = Set([ "deepracer-us-east-1" ]) } final class AWSDeviceFarm: AWSNamedService, SubService { let name = "AWS Device Farm" let ids = Set([ "devicefarm-us-west-2" ]) } final class AWSDirectConnect: AWSNamedService, SubService { let name = "AWS Direct Connect" let ids = Set([ "directconnect-af-south-1", "directconnect-ap-east-1", "directconnect-ap-east-2", "directconnect-ap-northeast-1", "directconnect-ap-northeast-2", "directconnect-ap-northeast-3", "directconnect-ap-south-1", "directconnect-ap-south-2", "directconnect-ap-southeast-1", "directconnect-ap-southeast-2", "directconnect-ap-southeast-3", "directconnect-ap-southeast-4", "directconnect-ap-southeast-5", "directconnect-ap-southeast-6", "directconnect-ap-southeast-7", "directconnect-ca-central-1", "directconnect-ca-west-1", "directconnect-eu-central-1", "directconnect-eu-central-2", "directconnect-eu-north-1", "directconnect-eu-south-1", "directconnect-eu-south-2", "directconnect-eu-west-1", "directconnect-eu-west-2", "directconnect-eu-west-3", "directconnect-il-central-1", "directconnect-me-central-1", "directconnect-me-south-1", "directconnect-mx-central-1", "directconnect-sa-east-1", "directconnect-us-east-1", "directconnect-us-east-2", "directconnect-us-gov-east-1", "directconnect-us-gov-west-1", "directconnect-us-west-1", "directconnect-us-west-2" ]) } final class AWSDirectoryService: AWSNamedService, SubService { let name = "AWS Directory Service" let ids = Set([ "directoryservice-af-south-1", "directoryservice-ap-east-1", "directoryservice-ap-east-2", "directoryservice-ap-northeast-1", "directoryservice-ap-northeast-2", "directoryservice-ap-northeast-3", "directoryservice-ap-south-1", "directoryservice-ap-south-2", "directoryservice-ap-southeast-1", "directoryservice-ap-southeast-2", "directoryservice-ap-southeast-3", "directoryservice-ap-southeast-4", "directoryservice-ap-southeast-5", "directoryservice-ap-southeast-6", "directoryservice-ap-southeast-7", "directoryservice-ca-central-1", "directoryservice-ca-west-1", "directoryservice-eu-central-1", "directoryservice-eu-central-2", "directoryservice-eu-north-1", "directoryservice-eu-south-1", "directoryservice-eu-south-2", "directoryservice-eu-west-1", "directoryservice-eu-west-2", "directoryservice-eu-west-3", "directoryservice-il-central-1", "directoryservice-me-central-1", "directoryservice-me-south-1", "directoryservice-mx-central-1", "directoryservice-sa-east-1", "directoryservice-us-east-1", "directoryservice-us-east-2", "directoryservice-us-gov-east-1", "directoryservice-us-gov-west-1", "directoryservice-us-west-1", "directoryservice-us-west-2" ]) } final class AWSEC2ImageBuilder: AWSNamedService, SubService { let name = "AWS EC2 Image Builder" let ids = Set([ "imagebuilder-af-south-1", "imagebuilder-ap-east-1", "imagebuilder-ap-east-2", "imagebuilder-ap-northeast-1", "imagebuilder-ap-northeast-2", "imagebuilder-ap-northeast-3", "imagebuilder-ap-south-1", "imagebuilder-ap-south-2", "imagebuilder-ap-southeast-1", "imagebuilder-ap-southeast-2", "imagebuilder-ap-southeast-3", "imagebuilder-ap-southeast-4", "imagebuilder-ap-southeast-5", "imagebuilder-ap-southeast-6", "imagebuilder-ap-southeast-7", "imagebuilder-ca-central-1", "imagebuilder-ca-west-1", "imagebuilder-eu-central-1", "imagebuilder-eu-central-2", "imagebuilder-eu-north-1", "imagebuilder-eu-south-1", "imagebuilder-eu-south-2", "imagebuilder-eu-west-1", "imagebuilder-eu-west-2", "imagebuilder-eu-west-3", "imagebuilder-il-central-1", "imagebuilder-me-central-1", "imagebuilder-me-south-1", "imagebuilder-mx-central-1", "imagebuilder-sa-east-1", "imagebuilder-us-east-1", "imagebuilder-us-east-2", "imagebuilder-us-gov-east-1", "imagebuilder-us-gov-west-1", "imagebuilder-us-west-1", "imagebuilder-us-west-2" ]) } final class AWSEC2SerialConsole: AWSNamedService, SubService { let name = "AWS EC2 Serial Console" let ids = Set([ "ec2serialconsole-af-south-1", "ec2serialconsole-ap-east-1", "ec2serialconsole-ap-northeast-1", "ec2serialconsole-ap-northeast-2", "ec2serialconsole-ap-northeast-3", "ec2serialconsole-ap-south-1", "ec2serialconsole-ap-south-2", "ec2serialconsole-ap-southeast-1", "ec2serialconsole-ap-southeast-2", "ec2serialconsole-ap-southeast-3", "ec2serialconsole-ap-southeast-4", "ec2serialconsole-ap-southeast-5", "ec2serialconsole-ap-southeast-7", "ec2serialconsole-ca-central-1", "ec2serialconsole-ca-west-1", "ec2serialconsole-eu-central-1", "ec2serialconsole-eu-central-2", "ec2serialconsole-eu-north-1", "ec2serialconsole-eu-south-1", "ec2serialconsole-eu-south-2", "ec2serialconsole-eu-west-1", "ec2serialconsole-eu-west-2", "ec2serialconsole-eu-west-3", "ec2serialconsole-il-central-1", "ec2serialconsole-me-central-1", "ec2serialconsole-me-south-1", "ec2serialconsole-mx-central-1", "ec2serialconsole-sa-east-1", "ec2serialconsole-us-east-1", "ec2serialconsole-us-east-2", "ec2serialconsole-us-gov-east-1", "ec2serialconsole-us-gov-west-1", "ec2serialconsole-us-west-1", "ec2serialconsole-us-west-2" ]) } final class AWSElasticBeanstalk: AWSNamedService, SubService { let name = "AWS Elastic Beanstalk" let ids = Set([ "elasticbeanstalk-af-south-1", "elasticbeanstalk-ap-east-1", "elasticbeanstalk-ap-northeast-1", "elasticbeanstalk-ap-northeast-2", "elasticbeanstalk-ap-northeast-3", "elasticbeanstalk-ap-south-1", "elasticbeanstalk-ap-south-2", "elasticbeanstalk-ap-southeast-1", "elasticbeanstalk-ap-southeast-2", "elasticbeanstalk-ap-southeast-3", "elasticbeanstalk-ap-southeast-4", "elasticbeanstalk-ap-southeast-5", "elasticbeanstalk-ap-southeast-6", "elasticbeanstalk-ap-southeast-7", "elasticbeanstalk-ca-central-1", "elasticbeanstalk-ca-west-1", "elasticbeanstalk-eu-central-1", "elasticbeanstalk-eu-central-2", "elasticbeanstalk-eu-north-1", "elasticbeanstalk-eu-south-1", "elasticbeanstalk-eu-south-2", "elasticbeanstalk-eu-west-1", "elasticbeanstalk-eu-west-2", "elasticbeanstalk-eu-west-3", "elasticbeanstalk-il-central-1", "elasticbeanstalk-me-central-1", "elasticbeanstalk-me-south-1", "elasticbeanstalk-sa-east-1", "elasticbeanstalk-us-east-1", "elasticbeanstalk-us-east-2", "elasticbeanstalk-us-gov-east-1", "elasticbeanstalk-us-gov-west-1", "elasticbeanstalk-us-west-1", "elasticbeanstalk-us-west-2" ]) } final class AWSElasticDisasterRecovery: AWSNamedService, SubService { let name = "AWS Elastic Disaster Recovery" let ids = Set([ "drs-af-south-1", "drs-ap-east-1", "drs-ap-northeast-1", "drs-ap-northeast-2", "drs-ap-northeast-3", "drs-ap-south-1", "drs-ap-south-2", "drs-ap-southeast-1", "drs-ap-southeast-2", "drs-ap-southeast-3", "drs-ap-southeast-4", "drs-ca-central-1", "drs-eu-central-1", "drs-eu-central-2", "drs-eu-north-1", "drs-eu-south-1", "drs-eu-south-2", "drs-eu-west-1", "drs-eu-west-2", "drs-eu-west-3", "drs-il-central-1", "drs-me-central-1", "drs-me-south-1", "drs-sa-east-1", "drs-us-east-1", "drs-us-east-2", "drs-us-gov-east-1", "drs-us-gov-west-1", "drs-us-west-1", "drs-us-west-2" ]) } final class AWSElasticVMWareService: AWSNamedService, SubService { let name = "AWS Elastic VMWare Service" let ids = Set([ "evs-ap-northeast-1", "evs-ap-south-1", "evs-ap-south-2", "evs-ap-southeast-1", "evs-ap-southeast-2", "evs-ap-southeast-5", "evs-ca-central-1", "evs-ca-west-1", "evs-eu-central-1", "evs-eu-south-1", "evs-eu-west-1", "evs-eu-west-2", "evs-eu-west-3", "evs-mx-central-1", "evs-sa-east-1", "evs-us-east-1", "evs-us-east-2", "evs-us-west-1", "evs-us-west-2" ]) } final class AWSElemental: AWSNamedService, SubService { let name = "AWS Elemental" let ids = Set([ "elemental-af-south-1", "elemental-ap-east-1", "elemental-ap-northeast-1", "elemental-ap-northeast-2", "elemental-ap-northeast-3", "elemental-ap-south-1", "elemental-ap-south-2", "elemental-ap-southeast-1", "elemental-ap-southeast-2", "elemental-ap-southeast-4", "elemental-ap-southeast-5", "elemental-ca-central-1", "elemental-eu-central-1", "elemental-eu-north-1", "elemental-eu-west-1", "elemental-eu-west-2", "elemental-eu-west-3", "elemental-me-central-1", "elemental-sa-east-1", "elemental-us-east-1", "elemental-us-east-2", "elemental-us-gov-west-1", "elemental-us-west-1", "elemental-us-west-2" ]) } final class AWSEndUserMessaging: AWSNamedService, SubService { let name = "AWS End User Messaging" let ids = Set([ "endusermessaging-af-south-1", "endusermessaging-ap-east-2", "endusermessaging-ap-northeast-1", "endusermessaging-ap-northeast-2", "endusermessaging-ap-northeast-3", "endusermessaging-ap-south-1", "endusermessaging-ap-south-2", "endusermessaging-ap-southeast-1", "endusermessaging-ap-southeast-2", "endusermessaging-ap-southeast-3", "endusermessaging-ap-southeast-4", "endusermessaging-ap-southeast-6", "endusermessaging-ca-central-1", "endusermessaging-ca-west-1", "endusermessaging-eu-central-1", "endusermessaging-eu-central-2", "endusermessaging-eu-north-1", "endusermessaging-eu-south-1", "endusermessaging-eu-south-2", "endusermessaging-eu-west-1", "endusermessaging-eu-west-2", "endusermessaging-eu-west-3", "endusermessaging-il-central-1", "endusermessaging-me-central-1", "endusermessaging-me-south-1", "endusermessaging-mx-central-1", "endusermessaging-sa-east-1", "endusermessaging-us-east-1", "endusermessaging-us-east-2", "endusermessaging-us-gov-east-1", "endusermessaging-us-gov-west-1", "endusermessaging-us-west-1", "endusermessaging-us-west-2" ]) } final class AWSEntityResolution: AWSNamedService, SubService { let name = "AWS Entity Resolution" let ids = Set([ "entityresolution-af-south-1", "entityresolution-ap-northeast-1", "entityresolution-ap-northeast-2", "entityresolution-ap-southeast-1", "entityresolution-ap-southeast-2", "entityresolution-ca-central-1", "entityresolution-eu-central-1", "entityresolution-eu-west-1", "entityresolution-eu-west-2", "entityresolution-us-east-1", "entityresolution-us-east-2", "entityresolution-us-west-2" ]) } final class AWSFargate: AWSNamedService, SubService { let name = "AWS Fargate" let ids = Set([ "fargate-af-south-1", "fargate-ap-east-1", "fargate-ap-east-2", "fargate-ap-northeast-1", "fargate-ap-northeast-2", "fargate-ap-northeast-3", "fargate-ap-south-1", "fargate-ap-south-2", "fargate-ap-southeast-1", "fargate-ap-southeast-2", "fargate-ap-southeast-3", "fargate-ap-southeast-4", "fargate-ap-southeast-5", "fargate-ap-southeast-6", "fargate-ap-southeast-7", "fargate-ca-central-1", "fargate-ca-west-1", "fargate-eu-central-1", "fargate-eu-central-2", "fargate-eu-north-1", "fargate-eu-south-1", "fargate-eu-south-2", "fargate-eu-west-1", "fargate-eu-west-2", "fargate-eu-west-3", "fargate-il-central-1", "fargate-me-central-1", "fargate-me-south-1", "fargate-mx-central-1", "fargate-sa-east-1", "fargate-us-east-1", "fargate-us-east-2", "fargate-us-gov-east-1", "fargate-us-gov-west-1", "fargate-us-west-1", "fargate-us-west-2" ]) } final class AWSFaultInjectionService: AWSNamedService, SubService { let name = "AWS Fault Injection Service" let ids = Set([ "fis-af-south-1", "fis-ap-east-1", "fis-ap-northeast-1", "fis-ap-northeast-2", "fis-ap-northeast-3", "fis-ap-south-1", "fis-ap-southeast-1", "fis-ap-southeast-2", "fis-ca-central-1", "fis-eu-central-1", "fis-eu-central-2", "fis-eu-north-1", "fis-eu-south-1", "fis-eu-south-2", "fis-eu-west-1", "fis-eu-west-2", "fis-eu-west-3", "fis-me-central-1", "fis-me-south-1", "fis-sa-east-1", "fis-us-east-1", "fis-us-east-2", "fis-us-gov-east-1", "fis-us-gov-west-1", "fis-us-west-1", "fis-us-west-2" ]) } final class AWSFirewallManager: AWSNamedService, SubService { let name = "AWS Firewall Manager" let ids = Set([ "fms-af-south-1", "fms-ap-east-1", "fms-ap-east-2", "fms-ap-northeast-1", "fms-ap-northeast-2", "fms-ap-northeast-3", "fms-ap-south-1", "fms-ap-south-2", "fms-ap-southeast-1", "fms-ap-southeast-2", "fms-ap-southeast-3", "fms-ap-southeast-4", "fms-ap-southeast-5", "fms-ap-southeast-6", "fms-ap-southeast-7", "fms-ca-central-1", "fms-ca-west-1", "fms-eu-central-1", "fms-eu-central-2", "fms-eu-north-1", "fms-eu-south-1", "fms-eu-south-2", "fms-eu-west-1", "fms-eu-west-2", "fms-eu-west-3", "fms-il-central-1", "fms-me-central-1", "fms-me-south-1", "fms-mx-central-1", "fms-sa-east-1", "fms-us-east-1", "fms-us-east-2", "fms-us-gov-east-1", "fms-us-gov-west-1", "fms-us-west-1", "fms-us-west-2" ]) } final class AWSGlobalAccelerator: AWSNamedService, SubService { let name = "AWS Global Accelerator" let ids = Set([ "globalaccelerator" ]) } final class AWSGlue: AWSNamedService, SubService { let name = "AWS Glue" let ids = Set([ "glue-af-south-1", "glue-ap-east-1", "glue-ap-east-2", "glue-ap-northeast-1", "glue-ap-northeast-2", "glue-ap-northeast-3", "glue-ap-south-1", "glue-ap-south-2", "glue-ap-southeast-1", "glue-ap-southeast-2", "glue-ap-southeast-3", "glue-ap-southeast-4", "glue-ap-southeast-5", "glue-ap-southeast-6", "glue-ap-southeast-7", "glue-ca-central-1", "glue-ca-west-1", "glue-eu-central-1", "glue-eu-central-2", "glue-eu-north-1", "glue-eu-south-1", "glue-eu-south-2", "glue-eu-west-1", "glue-eu-west-2", "glue-eu-west-3", "glue-il-central-1", "glue-me-central-1", "glue-me-south-1", "glue-mx-central-1", "glue-sa-east-1", "glue-us-east-1", "glue-us-east-2", "glue-us-gov-east-1", "glue-us-gov-west-1", "glue-us-west-1", "glue-us-west-2" ]) } final class AWSGlueDataBrew: AWSNamedService, SubService { let name = "AWS Glue DataBrew" let ids = Set([ "aws-glue-af-south-1", "aws-glue-ap-east-1", "aws-glue-ap-northeast-1", "aws-glue-ap-northeast-2", "aws-glue-ap-south-1", "aws-glue-ap-southeast-1", "aws-glue-ap-southeast-2", "aws-glue-ca-central-1", "aws-glue-eu-central-1", "aws-glue-eu-north-1", "aws-glue-eu-south-1", "aws-glue-eu-west-1", "aws-glue-eu-west-2", "aws-glue-eu-west-3", "aws-glue-sa-east-1", "aws-glue-us-east-1", "aws-glue-us-east-2", "aws-glue-us-gov-west-1", "aws-glue-us-west-1", "aws-glue-us-west-2" ]) } final class AWSGroundStation: AWSNamedService, SubService { let name = "AWS Ground Station" let ids = Set([ "groundstation-af-south-1", "groundstation-ap-northeast-2", "groundstation-ap-southeast-1", "groundstation-ap-southeast-2", "groundstation-eu-central-1", "groundstation-eu-north-1", "groundstation-eu-west-1", "groundstation-me-south-1", "groundstation-sa-east-1", "groundstation-us-east-1", "groundstation-us-east-2", "groundstation-us-west-2" ]) } final class AWSHealth: AWSNamedService, SubService { let name = "AWS Health" let ids = Set([ "health", "health-us-gov-east-1", "health-us-gov-west-1" ]) } final class AWSHealthImaging: AWSNamedService, SubService { let name = "AWS HealthImaging" let ids = Set([ "healthimaging-ap-southeast-2", "healthimaging-eu-west-1", "healthimaging-us-east-1", "healthimaging-us-west-2" ]) } final class AWSHealthLake: AWSNamedService, SubService { let name = "AWS HealthLake" let ids = Set([ "healthlake-ap-south-1", "healthlake-ap-southeast-2", "healthlake-ca-central-1", "healthlake-eu-west-1", "healthlake-eu-west-2", "healthlake-us-east-1", "healthlake-us-east-2", "healthlake-us-west-2" ]) } final class AWSHealthOmics: AWSNamedService, SubService { let name = "AWS HealthOmics" let ids = Set([ "omics-ap-northeast-2", "omics-ap-southeast-1", "omics-eu-central-1", "omics-eu-west-1", "omics-eu-west-2", "omics-il-central-1", "omics-us-east-1", "omics-us-west-2" ]) } final class AWSIAMIdentityCenter: AWSNamedService, SubService { let name = "AWS IAM Identity Center" let ids = Set([ "iamidentitycenter-af-south-1", "iamidentitycenter-ap-east-1", "iamidentitycenter-ap-east-2", "iamidentitycenter-ap-northeast-1", "iamidentitycenter-ap-northeast-2", "iamidentitycenter-ap-northeast-3", "iamidentitycenter-ap-south-1", "iamidentitycenter-ap-south-2", "iamidentitycenter-ap-southeast-1", "iamidentitycenter-ap-southeast-2", "iamidentitycenter-ap-southeast-3", "iamidentitycenter-ap-southeast-4", "iamidentitycenter-ap-southeast-5", "iamidentitycenter-ap-southeast-6", "iamidentitycenter-ap-southeast-7", "iamidentitycenter-ca-central-1", "iamidentitycenter-ca-west-1", "iamidentitycenter-eu-central-1", "iamidentitycenter-eu-central-2", "iamidentitycenter-eu-north-1", "iamidentitycenter-eu-south-1", "iamidentitycenter-eu-south-2", "iamidentitycenter-eu-west-1", "iamidentitycenter-eu-west-2", "iamidentitycenter-eu-west-3", "iamidentitycenter-il-central-1", "iamidentitycenter-me-central-1", "iamidentitycenter-me-south-1", "iamidentitycenter-mx-central-1", "iamidentitycenter-sa-east-1", "iamidentitycenter-us-east-1", "iamidentitycenter-us-east-2", "iamidentitycenter-us-gov-east-1", "iamidentitycenter-us-gov-west-1", "iamidentitycenter-us-west-1", "iamidentitycenter-us-west-2" ]) } final class AWSIdentityAndAccessManagement: AWSNamedService, SubService { let name = "AWS Identity and Access Management" let ids = Set([ "iam", "iam-us-gov-east-1", "iam-us-gov-west-1" ]) } final class AWSIdentityAndAccessManagementRolesAnywhere: AWSNamedService, SubService { let name = "AWS Identity and Access Management Roles Anywhere" let ids = Set([ "iamrolesanywhere-af-south-1", "iamrolesanywhere-ap-east-1", "iamrolesanywhere-ap-east-2", "iamrolesanywhere-ap-northeast-1", "iamrolesanywhere-ap-northeast-2", "iamrolesanywhere-ap-northeast-3", "iamrolesanywhere-ap-south-1", "iamrolesanywhere-ap-south-2", "iamrolesanywhere-ap-southeast-1", "iamrolesanywhere-ap-southeast-2", "iamrolesanywhere-ap-southeast-3", "iamrolesanywhere-ap-southeast-4", "iamrolesanywhere-ap-southeast-5", "iamrolesanywhere-ap-southeast-6", "iamrolesanywhere-ap-southeast-7", "iamrolesanywhere-ca-central-1", "iamrolesanywhere-ca-west-1", "iamrolesanywhere-eu-central-1", "iamrolesanywhere-eu-central-2", "iamrolesanywhere-eu-north-1", "iamrolesanywhere-eu-south-1", "iamrolesanywhere-eu-south-2", "iamrolesanywhere-eu-west-1", "iamrolesanywhere-eu-west-2", "iamrolesanywhere-eu-west-3", "iamrolesanywhere-il-central-1", "iamrolesanywhere-me-central-1", "iamrolesanywhere-me-south-1", "iamrolesanywhere-mx-central-1", "iamrolesanywhere-sa-east-1", "iamrolesanywhere-us-east-1", "iamrolesanywhere-us-east-2", "iamrolesanywhere-us-gov-east-1", "iamrolesanywhere-us-gov-west-1", "iamrolesanywhere-us-west-1", "iamrolesanywhere-us-west-2" ]) } final class AWSImportExport: AWSNamedService, SubService { let name = "AWS Import/Export" let ids = Set([ "import-export", "import-export-us-gov-east-1", "import-export-us-gov-west-1" ]) } final class AWSInfrastructurePerformance: AWSNamedService, SubService { let name = "AWS Infrastructure Performance" let ids = Set([ "infrastructureperformance-af-south-1", "infrastructureperformance-ap-east-1", "infrastructureperformance-ap-northeast-1", "infrastructureperformance-ap-northeast-2", "infrastructureperformance-ap-northeast-3", "infrastructureperformance-ap-south-1", "infrastructureperformance-ap-south-2", "infrastructureperformance-ap-southeast-1", "infrastructureperformance-ap-southeast-2", "infrastructureperformance-ap-southeast-3", "infrastructureperformance-ap-southeast-4", "infrastructureperformance-ca-central-1", "infrastructureperformance-eu-central-1", "infrastructureperformance-eu-central-2", "infrastructureperformance-eu-north-1", "infrastructureperformance-eu-south-1", "infrastructureperformance-eu-south-2", "infrastructureperformance-eu-west-1", "infrastructureperformance-eu-west-2", "infrastructureperformance-eu-west-3", "infrastructureperformance-me-central-1", "infrastructureperformance-me-south-1", "infrastructureperformance-sa-east-1", "infrastructureperformance-us-east-1", "infrastructureperformance-us-east-2", "infrastructureperformance-us-west-1", "infrastructureperformance-us-west-2" ]) } final class AWSInternetConnectivity: AWSNamedService, SubService { let name = "AWS Internet Connectivity" let ids = Set([ "internetconnectivity-af-south-1", "internetconnectivity-ap-east-1", "internetconnectivity-ap-east-2", "internetconnectivity-ap-northeast-1", "internetconnectivity-ap-northeast-2", "internetconnectivity-ap-northeast-3", "internetconnectivity-ap-south-1", "internetconnectivity-ap-south-2", "internetconnectivity-ap-southeast-1", "internetconnectivity-ap-southeast-2", "internetconnectivity-ap-southeast-3", "internetconnectivity-ap-southeast-4", "internetconnectivity-ap-southeast-5", "internetconnectivity-ap-southeast-6", "internetconnectivity-ap-southeast-7", "internetconnectivity-ca-central-1", "internetconnectivity-ca-west-1", "internetconnectivity-eu-central-1", "internetconnectivity-eu-central-2", "internetconnectivity-eu-north-1", "internetconnectivity-eu-south-1", "internetconnectivity-eu-south-2", "internetconnectivity-eu-west-1", "internetconnectivity-eu-west-2", "internetconnectivity-eu-west-3", "internetconnectivity-il-central-1", "internetconnectivity-me-central-1", "internetconnectivity-me-south-1", "internetconnectivity-mx-central-1", "internetconnectivity-sa-east-1", "internetconnectivity-us-east-1", "internetconnectivity-us-east-2", "internetconnectivity-us-gov-east-1", "internetconnectivity-us-gov-west-1", "internetconnectivity-us-west-1", "internetconnectivity-us-west-2" ]) } final class AWSIoTAnalytics: AWSNamedService, SubService { let name = "AWS IoT Analytics" let ids = Set([ "iotanalytics-ap-northeast-1", "iotanalytics-ap-south-1", "iotanalytics-ap-southeast-2", "iotanalytics-eu-central-1", "iotanalytics-eu-west-1", "iotanalytics-us-east-1", "iotanalytics-us-east-2", "iotanalytics-us-west-2" ]) } final class AWSIoTCore: AWSNamedService, SubService { let name = "AWS IoT Core" let ids = Set([ "awsiot-ap-east-1", "awsiot-ap-northeast-1", "awsiot-ap-northeast-2", "awsiot-ap-south-1", "awsiot-ap-southeast-1", "awsiot-ap-southeast-2", "awsiot-ap-southeast-5", "awsiot-ca-central-1", "awsiot-eu-central-1", "awsiot-eu-north-1", "awsiot-eu-south-2", "awsiot-eu-west-1", "awsiot-eu-west-2", "awsiot-eu-west-3", "awsiot-me-central-1", "awsiot-me-south-1", "awsiot-sa-east-1", "awsiot-us-east-1", "awsiot-us-east-2", "awsiot-us-gov-east-1", "awsiot-us-gov-west-1", "awsiot-us-west-1", "awsiot-us-west-2" ]) } final class AWSIoTDeviceDefender: AWSNamedService, SubService { let name = "AWS IoT Device Defender" let ids = Set([ "iotdevicedefender-ap-east-1", "iotdevicedefender-ap-northeast-1", "iotdevicedefender-ap-northeast-2", "iotdevicedefender-ap-south-1", "iotdevicedefender-ap-southeast-1", "iotdevicedefender-ap-southeast-2", "iotdevicedefender-ap-southeast-5", "iotdevicedefender-ca-central-1", "iotdevicedefender-eu-central-1", "iotdevicedefender-eu-north-1", "iotdevicedefender-eu-south-2", "iotdevicedefender-eu-west-1", "iotdevicedefender-eu-west-2", "iotdevicedefender-eu-west-3", "iotdevicedefender-me-central-1", "iotdevicedefender-me-south-1", "iotdevicedefender-us-east-1", "iotdevicedefender-us-east-2", "iotdevicedefender-us-gov-east-1", "iotdevicedefender-us-gov-west-1", "iotdevicedefender-us-west-1", "iotdevicedefender-us-west-2" ]) } final class AWSIoTDeviceManagement: AWSNamedService, SubService { let name = "AWS IoT Device Management" let ids = Set([ "awsiotdevicemanagement-ap-east-1", "awsiotdevicemanagement-ap-northeast-1", "awsiotdevicemanagement-ap-northeast-2", "awsiotdevicemanagement-ap-south-1", "awsiotdevicemanagement-ap-southeast-1", "awsiotdevicemanagement-ap-southeast-2", "awsiotdevicemanagement-ca-central-1", "awsiotdevicemanagement-eu-central-1", "awsiotdevicemanagement-eu-north-1", "awsiotdevicemanagement-eu-west-1", "awsiotdevicemanagement-eu-west-2", "awsiotdevicemanagement-eu-west-3", "awsiotdevicemanagement-me-central-1", "awsiotdevicemanagement-me-south-1", "awsiotdevicemanagement-sa-east-1", "awsiotdevicemanagement-us-east-1", "awsiotdevicemanagement-us-east-2", "awsiotdevicemanagement-us-gov-east-1", "awsiotdevicemanagement-us-gov-west-1", "awsiotdevicemanagement-us-west-1", "awsiotdevicemanagement-us-west-2" ]) } final class AWSIoTEvents: AWSNamedService, SubService { let name = "AWS IoT Events" let ids = Set([ "iotevents-ap-northeast-1", "iotevents-ap-northeast-2", "iotevents-ap-south-1", "iotevents-ap-southeast-1", "iotevents-ap-southeast-2", "iotevents-ca-central-1", "iotevents-eu-central-1", "iotevents-eu-west-1", "iotevents-eu-west-2", "iotevents-us-east-1", "iotevents-us-east-2", "iotevents-us-gov-west-1", "iotevents-us-west-2" ]) } final class AWSIoTFleetWise: AWSNamedService, SubService { let name = "AWS IoT FleetWise" let ids = Set([ "iotfleetwise-ap-south-1", "iotfleetwise-eu-central-1", "iotfleetwise-us-east-1" ]) } final class AWSIoTGreengrass: AWSNamedService, SubService { let name = "AWS IoT Greengrass" let ids = Set([ "awsgreengrass-ap-northeast-1", "awsgreengrass-ap-northeast-2", "awsgreengrass-ap-south-1", "awsgreengrass-ap-southeast-1", "awsgreengrass-ap-southeast-2", "awsgreengrass-ap-southeast-5", "awsgreengrass-ca-central-1", "awsgreengrass-eu-central-1", "awsgreengrass-eu-south-2", "awsgreengrass-eu-west-1", "awsgreengrass-eu-west-2", "awsgreengrass-us-east-1", "awsgreengrass-us-east-2", "awsgreengrass-us-gov-east-1", "awsgreengrass-us-gov-west-1", "awsgreengrass-us-west-2" ]) } final class AWSIoTSiteWise: AWSNamedService, SubService { let name = "AWS IoT SiteWise" let ids = Set([ "iotsitewise-ap-northeast-1", "iotsitewise-ap-northeast-2", "iotsitewise-ap-south-1", "iotsitewise-ap-southeast-1", "iotsitewise-ap-southeast-2", "iotsitewise-ca-central-1", "iotsitewise-eu-central-1", "iotsitewise-eu-west-1", "iotsitewise-us-east-1", "iotsitewise-us-east-2", "iotsitewise-us-gov-west-1", "iotsitewise-us-west-2" ]) } final class AWSIoTTwinMaker: AWSNamedService, SubService { let name = "AWS IoT TwinMaker" let ids = Set([ "iottwinmaker-ap-northeast-1", "iottwinmaker-ap-northeast-2", "iottwinmaker-ap-south-1", "iottwinmaker-ap-southeast-1", "iottwinmaker-ap-southeast-2", "iottwinmaker-eu-central-1", "iottwinmaker-eu-west-1", "iottwinmaker-us-east-1", "iottwinmaker-us-gov-west-1", "iottwinmaker-us-west-2" ]) } final class AWSKeyManagementService: AWSNamedService, SubService { let name = "AWS Key Management Service" let ids = Set([ "kms-af-south-1", "kms-ap-east-1", "kms-ap-east-2", "kms-ap-northeast-1", "kms-ap-northeast-2", "kms-ap-northeast-3", "kms-ap-south-1", "kms-ap-south-2", "kms-ap-southeast-1", "kms-ap-southeast-2", "kms-ap-southeast-3", "kms-ap-southeast-4", "kms-ap-southeast-5", "kms-ap-southeast-6", "kms-ap-southeast-7", "kms-ca-central-1", "kms-ca-west-1", "kms-eu-central-1", "kms-eu-central-2", "kms-eu-north-1", "kms-eu-south-1", "kms-eu-south-2", "kms-eu-west-1", "kms-eu-west-2", "kms-eu-west-3", "kms-il-central-1", "kms-me-central-1", "kms-me-south-1", "kms-mx-central-1", "kms-sa-east-1", "kms-us-east-1", "kms-us-east-2", "kms-us-gov-east-1", "kms-us-gov-west-1", "kms-us-west-1", "kms-us-west-2" ]) } final class AWSKiro: AWSNamedService, SubService { let name = "AWS Kiro" let ids = Set([ "codewhisperer-us-east-1" ]) } final class AWSLakeFormation: AWSNamedService, SubService { let name = "AWS Lake Formation" let ids = Set([ "lakeformation-af-south-1", "lakeformation-ap-east-1", "lakeformation-ap-east-2", "lakeformation-ap-northeast-1", "lakeformation-ap-northeast-2", "lakeformation-ap-northeast-3", "lakeformation-ap-south-1", "lakeformation-ap-south-2", "lakeformation-ap-southeast-1", "lakeformation-ap-southeast-2", "lakeformation-ap-southeast-3", "lakeformation-ap-southeast-4", "lakeformation-ap-southeast-5", "lakeformation-ap-southeast-6", "lakeformation-ap-southeast-7", "lakeformation-ca-central-1", "lakeformation-ca-west-1", "lakeformation-eu-central-1", "lakeformation-eu-central-2", "lakeformation-eu-north-1", "lakeformation-eu-south-1", "lakeformation-eu-south-2", "lakeformation-eu-west-1", "lakeformation-eu-west-2", "lakeformation-eu-west-3", "lakeformation-il-central-1", "lakeformation-me-central-1", "lakeformation-me-south-1", "lakeformation-mx-central-1", "lakeformation-sa-east-1", "lakeformation-us-east-1", "lakeformation-us-east-2", "lakeformation-us-gov-east-1", "lakeformation-us-gov-west-1", "lakeformation-us-west-1", "lakeformation-us-west-2" ]) } final class AWSLambda: AWSNamedService, SubService { let name = "AWS Lambda" let ids = Set([ "lambda-af-south-1", "lambda-ap-east-1", "lambda-ap-east-2", "lambda-ap-northeast-1", "lambda-ap-northeast-2", "lambda-ap-northeast-3", "lambda-ap-south-1", "lambda-ap-south-2", "lambda-ap-southeast-1", "lambda-ap-southeast-2", "lambda-ap-southeast-3", "lambda-ap-southeast-4", "lambda-ap-southeast-5", "lambda-ap-southeast-6", "lambda-ap-southeast-7", "lambda-ca-central-1", "lambda-ca-west-1", "lambda-eu-central-1", "lambda-eu-central-2", "lambda-eu-north-1", "lambda-eu-south-1", "lambda-eu-south-2", "lambda-eu-west-1", "lambda-eu-west-2", "lambda-eu-west-3", "lambda-il-central-1", "lambda-me-central-1", "lambda-me-south-1", "lambda-mx-central-1", "lambda-sa-east-1", "lambda-us-east-1", "lambda-us-east-2", "lambda-us-gov-east-1", "lambda-us-gov-west-1", "lambda-us-west-1", "lambda-us-west-2" ]) } final class AWSLaunchWizard: AWSNamedService, SubService { let name = "AWS Launch Wizard" let ids = Set([ "appwizard-af-south-1", "appwizard-ap-east-1", "appwizard-ap-northeast-1", "appwizard-ap-northeast-2", "appwizard-ap-northeast-3", "appwizard-ap-south-1", "appwizard-ap-south-2", "appwizard-ap-southeast-1", "appwizard-ap-southeast-2", "appwizard-ap-southeast-3", "appwizard-ap-southeast-4", "appwizard-ca-central-1", "appwizard-eu-central-1", "appwizard-eu-central-2", "appwizard-eu-north-1", "appwizard-eu-south-1", "appwizard-eu-south-2", "appwizard-eu-west-1", "appwizard-eu-west-2", "appwizard-eu-west-3", "appwizard-me-central-1", "appwizard-me-south-1", "appwizard-sa-east-1", "appwizard-us-east-1", "appwizard-us-east-2", "appwizard-us-gov-east-1", "appwizard-us-gov-west-1", "appwizard-us-west-1", "appwizard-us-west-2" ]) } final class AWSLicenseManager: AWSNamedService, SubService { let name = "AWS License Manager" let ids = Set([ "licensemanager-af-south-1", "licensemanager-ap-east-1", "licensemanager-ap-east-2", "licensemanager-ap-northeast-1", "licensemanager-ap-northeast-2", "licensemanager-ap-northeast-3", "licensemanager-ap-south-1", "licensemanager-ap-south-2", "licensemanager-ap-southeast-1", "licensemanager-ap-southeast-2", "licensemanager-ap-southeast-3", "licensemanager-ap-southeast-4", "licensemanager-ap-southeast-5", "licensemanager-ap-southeast-6", "licensemanager-ap-southeast-7", "licensemanager-ca-central-1", "licensemanager-ca-west-1", "licensemanager-eu-central-1", "licensemanager-eu-central-2", "licensemanager-eu-north-1", "licensemanager-eu-south-1", "licensemanager-eu-south-2", "licensemanager-eu-west-1", "licensemanager-eu-west-2", "licensemanager-eu-west-3", "licensemanager-il-central-1", "licensemanager-me-central-1", "licensemanager-me-south-1", "licensemanager-mx-central-1", "licensemanager-sa-east-1", "licensemanager-us-east-1", "licensemanager-us-east-2", "licensemanager-us-gov-east-1", "licensemanager-us-gov-west-1", "licensemanager-us-west-1", "licensemanager-us-west-2" ]) } final class AWSMainframeModernization: AWSNamedService, SubService { let name = "AWS Mainframe Modernization" let ids = Set([ "m2-af-south-1", "m2-ap-northeast-1", "m2-ap-northeast-2", "m2-ap-northeast-3", "m2-ap-south-1", "m2-ap-southeast-1", "m2-ap-southeast-2", "m2-ca-central-1", "m2-eu-central-1", "m2-eu-north-1", "m2-eu-south-1", "m2-eu-south-2", "m2-eu-west-1", "m2-eu-west-2", "m2-eu-west-3", "m2-il-central-1", "m2-sa-east-1", "m2-us-east-1", "m2-us-east-2", "m2-us-gov-east-1", "m2-us-gov-west-1", "m2-us-west-1", "m2-us-west-2" ]) } final class AWSManagementConsole: AWSNamedService, SubService { let name = "AWS Management Console" let ids = Set([ "management-console", "management-console-us-gov-east-1", "management-console-us-gov-west-1" ]) } final class AWSMarketplace: AWSNamedService, SubService { let name = "AWS Marketplace" let ids = Set([ "marketplace", "marketplace-us-gov-east-1", "marketplace-us-gov-west-1" ]) } final class AWSMigrationHub: AWSNamedService, SubService { let name = "AWS Migration Hub" let ids = Set([ "migrationhub-ap-northeast-1", "migrationhub-ap-southeast-2", "migrationhub-eu-central-1", "migrationhub-eu-west-1", "migrationhub-eu-west-2", "migrationhub-us-east-1", "migrationhub-us-west-2" ]) } final class AWSMigrationHubJourneys: AWSNamedService, SubService { let name = "AWS Migration Hub Journeys" let ids = Set([ "migops-eu-west-3", "migops-us-east-1", "migops-us-east-2" ]) } final class AWSMigrationHubOrchestrator: AWSNamedService, SubService { let name = "AWS Migration Hub Orchestrator" let ids = Set([ "migrationhuborchestrator-ap-northeast-1", "migrationhuborchestrator-ap-southeast-2", "migrationhuborchestrator-eu-central-1", "migrationhuborchestrator-eu-west-1", "migrationhuborchestrator-eu-west-2", "migrationhuborchestrator-us-east-1", "migrationhuborchestrator-us-west-2" ]) } final class AWSMigrationHubStrategyRecommendations: AWSNamedService, SubService { let name = "AWS Migration Hub Strategy Recommendations" let ids = Set([ "migrationhubstrategy-ap-northeast-1", "migrationhubstrategy-ap-southeast-2", "migrationhubstrategy-eu-central-1", "migrationhubstrategy-eu-west-1", "migrationhubstrategy-eu-west-2", "migrationhubstrategy-us-east-1", "migrationhubstrategy-us-west-2" ]) } final class AWSMultipleServices: AWSNamedService, SubService { let name = "AWS Multiple services" let ids = Set([ "multipleservices-af-south-1", "multipleservices-ap-east-1", "multipleservices-ap-east-2", "multipleservices-ap-northeast-1", "multipleservices-ap-northeast-2", "multipleservices-ap-northeast-3", "multipleservices-ap-south-1", "multipleservices-ap-south-2", "multipleservices-ap-southeast-1", "multipleservices-ap-southeast-2", "multipleservices-ap-southeast-3", "multipleservices-ap-southeast-4", "multipleservices-ap-southeast-5", "multipleservices-ap-southeast-6", "multipleservices-ap-southeast-7", "multipleservices-ca-central-1", "multipleservices-ca-west-1", "multipleservices-eu-central-1", "multipleservices-eu-central-2", "multipleservices-eu-north-1", "multipleservices-eu-south-1", "multipleservices-eu-south-2", "multipleservices-eu-west-1", "multipleservices-eu-west-2", "multipleservices-eu-west-3", "multipleservices-il-central-1", "multipleservices-me-central-1", "multipleservices-me-south-1", "multipleservices-mx-central-1", "multipleservices-sa-east-1", "multipleservices-us-east-1", "multipleservices-us-east-2", "multipleservices-us-west-1", "multipleservices-us-west-2" ]) } final class AWSNATGateway: AWSNamedService, SubService { let name = "AWS NAT Gateway" let ids = Set([ "natgateway-af-south-1", "natgateway-ap-east-1", "natgateway-ap-east-2", "natgateway-ap-northeast-1", "natgateway-ap-northeast-2", "natgateway-ap-northeast-3", "natgateway-ap-south-1", "natgateway-ap-south-2", "natgateway-ap-southeast-1", "natgateway-ap-southeast-2", "natgateway-ap-southeast-3", "natgateway-ap-southeast-4", "natgateway-ap-southeast-5", "natgateway-ap-southeast-6", "natgateway-ap-southeast-7", "natgateway-ca-central-1", "natgateway-ca-west-1", "natgateway-eu-central-1", "natgateway-eu-central-2", "natgateway-eu-north-1", "natgateway-eu-south-1", "natgateway-eu-south-2", "natgateway-eu-west-1", "natgateway-eu-west-2", "natgateway-eu-west-3", "natgateway-il-central-1", "natgateway-me-central-1", "natgateway-me-south-1", "natgateway-mx-central-1", "natgateway-sa-east-1", "natgateway-us-east-1", "natgateway-us-east-2", "natgateway-us-gov-east-1", "natgateway-us-gov-west-1", "natgateway-us-west-1", "natgateway-us-west-2" ]) } final class AWSNetworkAccessAnalyzer: AWSNamedService, SubService { let name = "AWS Network Access Analyzer" let ids = Set([ "networkaccessanalyzer-af-south-1", "networkaccessanalyzer-ap-east-1", "networkaccessanalyzer-ap-northeast-1", "networkaccessanalyzer-ap-northeast-2", "networkaccessanalyzer-ap-south-1", "networkaccessanalyzer-ap-southeast-1", "networkaccessanalyzer-ap-southeast-2", "networkaccessanalyzer-ca-central-1", "networkaccessanalyzer-eu-central-1", "networkaccessanalyzer-eu-north-1", "networkaccessanalyzer-eu-south-1", "networkaccessanalyzer-eu-west-1", "networkaccessanalyzer-eu-west-2", "networkaccessanalyzer-eu-west-3", "networkaccessanalyzer-me-south-1", "networkaccessanalyzer-sa-east-1", "networkaccessanalyzer-us-east-1", "networkaccessanalyzer-us-east-2", "networkaccessanalyzer-us-west-1", "networkaccessanalyzer-us-west-2" ]) } final class AWSNetworkFirewall: AWSNamedService, SubService { let name = "AWS Network Firewall" let ids = Set([ "networkfirewall-af-south-1", "networkfirewall-ap-east-1", "networkfirewall-ap-east-2", "networkfirewall-ap-northeast-1", "networkfirewall-ap-northeast-2", "networkfirewall-ap-northeast-3", "networkfirewall-ap-south-1", "networkfirewall-ap-south-2", "networkfirewall-ap-southeast-1", "networkfirewall-ap-southeast-2", "networkfirewall-ap-southeast-3", "networkfirewall-ap-southeast-4", "networkfirewall-ap-southeast-5", "networkfirewall-ap-southeast-6", "networkfirewall-ap-southeast-7", "networkfirewall-ca-central-1", "networkfirewall-ca-west-1", "networkfirewall-eu-central-1", "networkfirewall-eu-central-2", "networkfirewall-eu-north-1", "networkfirewall-eu-south-1", "networkfirewall-eu-south-2", "networkfirewall-eu-west-1", "networkfirewall-eu-west-2", "networkfirewall-eu-west-3", "networkfirewall-il-central-1", "networkfirewall-me-central-1", "networkfirewall-me-south-1", "networkfirewall-mx-central-1", "networkfirewall-sa-east-1", "networkfirewall-us-east-1", "networkfirewall-us-east-2", "networkfirewall-us-gov-east-1", "networkfirewall-us-gov-west-1", "networkfirewall-us-west-1", "networkfirewall-us-west-2" ]) } final class AWSOpsWorksStacks: AWSNamedService, SubService { let name = "AWS OpsWorks Stacks" let ids = Set([ "opsworks-ap-northeast-1", "opsworks-ap-northeast-2", "opsworks-ap-south-1", "opsworks-ap-southeast-1", "opsworks-ap-southeast-2", "opsworks-ca-central-1", "opsworks-eu-central-1", "opsworks-eu-west-1", "opsworks-eu-west-2", "opsworks-eu-west-3", "opsworks-sa-east-1", "opsworks-us-east-1", "opsworks-us-east-2", "opsworks-us-west-1", "opsworks-us-west-2" ]) } final class AWSOpsWorksForChefAutomate: AWSNamedService, SubService { let name = "AWS OpsWorks for Chef Automate" let ids = Set([ "opsworkschef-ap-northeast-1", "opsworkschef-ap-southeast-1", "opsworkschef-ap-southeast-2", "opsworkschef-eu-central-1", "opsworkschef-eu-west-1", "opsworkschef-us-east-1", "opsworkschef-us-east-2", "opsworkschef-us-west-1", "opsworkschef-us-west-2" ]) } final class AWSOpsWorksForPuppetEnterprise: AWSNamedService, SubService { let name = "AWS OpsWorks for Puppet Enterprise" let ids = Set([ "opsworkspuppet-ap-northeast-1", "opsworkspuppet-ap-southeast-1", "opsworkspuppet-ap-southeast-2", "opsworkspuppet-eu-central-1", "opsworkspuppet-eu-west-1", "opsworkspuppet-us-east-1", "opsworkspuppet-us-east-2", "opsworkspuppet-us-west-1", "opsworkspuppet-us-west-2" ]) } final class AWSOrganizations: AWSNamedService, SubService { let name = "AWS Organizations" let ids = Set([ "organizations", "organizations-us-gov-east-1", "organizations-us-gov-west-1" ]) } final class AWSOutposts: AWSNamedService, SubService { let name = "AWS Outposts" let ids = Set([ "outposts-af-south-1", "outposts-ap-east-1", "outposts-ap-northeast-1", "outposts-ap-northeast-2", "outposts-ap-northeast-3", "outposts-ap-south-1", "outposts-ap-southeast-1", "outposts-ap-southeast-2", "outposts-ap-southeast-3", "outposts-ca-central-1", "outposts-eu-central-1", "outposts-eu-north-1", "outposts-eu-south-1", "outposts-eu-south-2", "outposts-eu-west-1", "outposts-eu-west-2", "outposts-eu-west-3", "outposts-il-central-1", "outposts-me-central-1", "outposts-me-south-1", "outposts-mx-central-1", "outposts-sa-east-1", "outposts-us-east-1", "outposts-us-east-2", "outposts-us-gov-east-1", "outposts-us-gov-west-1", "outposts-us-west-1", "outposts-us-west-2" ]) } final class AWSPanorama: AWSNamedService, SubService { let name = "AWS Panorama" let ids = Set([ "panorama-ca-central-1", "panorama-eu-west-1", "panorama-us-east-1", "panorama-us-west-2" ]) } final class AWSParallelComputingService: AWSNamedService, SubService { let name = "AWS Parallel Computing Service" let ids = Set([ "pcs-ap-northeast-1", "pcs-ap-south-1", "pcs-ap-southeast-1", "pcs-ap-southeast-2", "pcs-eu-central-1", "pcs-eu-north-1", "pcs-eu-west-1", "pcs-eu-west-2", "pcs-eu-west-3", "pcs-us-east-1", "pcs-us-east-2", "pcs-us-gov-east-1", "pcs-us-gov-west-1", "pcs-us-west-2" ]) } final class AWSPartnerCentral: AWSNamedService, SubService { let name = "AWS Partner Central" let ids = Set([ "aws-partner-central", "aws-partner-central-us-gov-east-1", "aws-partner-central-us-gov-west-1" ]) } final class AWSPaymentCryptography: AWSNamedService, SubService { let name = "AWS Payment Cryptography" let ids = Set([ "paymentcryptography-af-south-1", "paymentcryptography-ap-northeast-1", "paymentcryptography-ap-northeast-3", "paymentcryptography-ap-south-1", "paymentcryptography-ap-south-2", "paymentcryptography-ap-southeast-1", "paymentcryptography-ap-southeast-2", "paymentcryptography-ca-central-1", "paymentcryptography-eu-central-1", "paymentcryptography-eu-west-1", "paymentcryptography-eu-west-2", "paymentcryptography-eu-west-3", "paymentcryptography-us-east-1", "paymentcryptography-us-east-2", "paymentcryptography-us-west-2" ]) } final class AWSPriceListService: AWSNamedService, SubService { let name = "AWS Price List Service" let ids = Set([ "apipricing-ap-south-1", "apipricing-eu-central-1", "apipricing-us-east-1" ]) } final class AWSPrivateCAConnectorForActiveDirectory: AWSNamedService, SubService { let name = "AWS Private CA Connector for Active Directory" let ids = Set([ "pcaconnectorad-af-south-1", "pcaconnectorad-ap-east-1", "pcaconnectorad-ap-east-2", "pcaconnectorad-ap-northeast-1", "pcaconnectorad-ap-northeast-2", "pcaconnectorad-ap-northeast-3", "pcaconnectorad-ap-south-1", "pcaconnectorad-ap-south-2", "pcaconnectorad-ap-southeast-1", "pcaconnectorad-ap-southeast-2", "pcaconnectorad-ap-southeast-3", "pcaconnectorad-ap-southeast-4", "pcaconnectorad-ap-southeast-5", "pcaconnectorad-ap-southeast-6", "pcaconnectorad-ap-southeast-7", "pcaconnectorad-ca-central-1", "pcaconnectorad-ca-west-1", "pcaconnectorad-eu-central-1", "pcaconnectorad-eu-central-2", "pcaconnectorad-eu-north-1", "pcaconnectorad-eu-south-1", "pcaconnectorad-eu-south-2", "pcaconnectorad-eu-west-1", "pcaconnectorad-eu-west-2", "pcaconnectorad-eu-west-3", "pcaconnectorad-il-central-1", "pcaconnectorad-me-central-1", "pcaconnectorad-me-south-1", "pcaconnectorad-mx-central-1", "pcaconnectorad-sa-east-1", "pcaconnectorad-us-east-1", "pcaconnectorad-us-east-2", "pcaconnectorad-us-west-1", "pcaconnectorad-us-west-2" ]) } final class AWSPrivateCAConnectorForSCEP: AWSNamedService, SubService { let name = "AWS Private CA Connector for SCEP" let ids = Set([ "pca-connector-scep-af-south-1", "pca-connector-scep-ap-east-1", "pca-connector-scep-ap-northeast-1", "pca-connector-scep-ap-northeast-2", "pca-connector-scep-ap-northeast-3", "pca-connector-scep-ap-south-1", "pca-connector-scep-ap-south-2", "pca-connector-scep-ap-southeast-1", "pca-connector-scep-ap-southeast-2", "pca-connector-scep-ap-southeast-3", "pca-connector-scep-ap-southeast-4", "pca-connector-scep-ap-southeast-5", "pca-connector-scep-ap-southeast-7", "pca-connector-scep-ca-central-1", "pca-connector-scep-ca-west-1", "pca-connector-scep-eu-central-1", "pca-connector-scep-eu-central-2", "pca-connector-scep-eu-north-1", "pca-connector-scep-eu-south-1", "pca-connector-scep-eu-south-2", "pca-connector-scep-eu-west-1", "pca-connector-scep-eu-west-2", "pca-connector-scep-eu-west-3", "pca-connector-scep-il-central-1", "pca-connector-scep-me-central-1", "pca-connector-scep-me-south-1", "pca-connector-scep-mx-central-1", "pca-connector-scep-sa-east-1", "pca-connector-scep-us-east-1", "pca-connector-scep-us-east-2", "pca-connector-scep-us-west-1", "pca-connector-scep-us-west-2" ]) } final class AWSPrivateCertificateAuthority: AWSNamedService, SubService { let name = "AWS Private Certificate Authority" let ids = Set([ "acm-pca-af-south-1", "acm-pca-ap-east-1", "acm-pca-ap-east-2", "acm-pca-ap-northeast-1", "acm-pca-ap-northeast-2", "acm-pca-ap-northeast-3", "acm-pca-ap-south-1", "acm-pca-ap-south-2", "acm-pca-ap-southeast-1", "acm-pca-ap-southeast-2", "acm-pca-ap-southeast-3", "acm-pca-ap-southeast-4", "acm-pca-ap-southeast-5", "acm-pca-ap-southeast-6", "acm-pca-ap-southeast-7", "acm-pca-ca-central-1", "acm-pca-ca-west-1", "acm-pca-eu-central-1", "acm-pca-eu-central-2", "acm-pca-eu-north-1", "acm-pca-eu-south-1", "acm-pca-eu-south-2", "acm-pca-eu-west-1", "acm-pca-eu-west-2", "acm-pca-eu-west-3", "acm-pca-il-central-1", "acm-pca-me-central-1", "acm-pca-me-south-1", "acm-pca-mx-central-1", "acm-pca-sa-east-1", "acm-pca-us-east-1", "acm-pca-us-east-2", "acm-pca-us-gov-east-1", "acm-pca-us-gov-west-1", "acm-pca-us-west-1", "acm-pca-us-west-2" ]) } final class AWSProton: AWSNamedService, SubService { let name = "AWS Proton" let ids = Set([ "proton-ap-northeast-1", "proton-ap-northeast-2", "proton-ap-southeast-1", "proton-ap-southeast-2", "proton-ca-central-1", "proton-eu-central-1", "proton-eu-west-1", "proton-eu-west-2", "proton-us-east-1", "proton-us-east-2", "proton-us-west-2" ]) } final class AWSRTBFabric: AWSNamedService, SubService { let name = "AWS RTB Fabric" let ids = Set([ "rtbfabric-ap-northeast-1", "rtbfabric-ap-southeast-1", "rtbfabric-eu-central-1", "rtbfabric-eu-west-1", "rtbfabric-us-east-1", "rtbfabric-us-west-2" ]) } final class AWSReachabilityAnalyzer: AWSNamedService, SubService { let name = "AWS Reachability Analyzer" let ids = Set([ "reachabilityanalyzer-af-south-1", "reachabilityanalyzer-ap-east-1", "reachabilityanalyzer-ap-northeast-1", "reachabilityanalyzer-ap-northeast-2", "reachabilityanalyzer-ap-south-1", "reachabilityanalyzer-ap-southeast-1", "reachabilityanalyzer-ap-southeast-2", "reachabilityanalyzer-ca-central-1", "reachabilityanalyzer-eu-central-1", "reachabilityanalyzer-eu-north-1", "reachabilityanalyzer-eu-south-1", "reachabilityanalyzer-eu-west-1", "reachabilityanalyzer-eu-west-2", "reachabilityanalyzer-eu-west-3", "reachabilityanalyzer-me-south-1", "reachabilityanalyzer-sa-east-1", "reachabilityanalyzer-us-east-1", "reachabilityanalyzer-us-east-2", "reachabilityanalyzer-us-west-1", "reachabilityanalyzer-us-west-2" ]) } final class AWSResilienceHub: AWSNamedService, SubService { let name = "AWS Resilience Hub" let ids = Set([ "resiliencehub-af-south-1", "resiliencehub-ap-east-1", "resiliencehub-ap-northeast-1", "resiliencehub-ap-northeast-2", "resiliencehub-ap-south-1", "resiliencehub-ap-southeast-1", "resiliencehub-ap-southeast-2", "resiliencehub-ca-central-1", "resiliencehub-eu-central-1", "resiliencehub-eu-north-1", "resiliencehub-eu-south-1", "resiliencehub-eu-west-1", "resiliencehub-eu-west-2", "resiliencehub-eu-west-3", "resiliencehub-me-south-1", "resiliencehub-sa-east-1", "resiliencehub-us-east-1", "resiliencehub-us-east-2", "resiliencehub-us-gov-east-1", "resiliencehub-us-gov-west-1", "resiliencehub-us-west-1", "resiliencehub-us-west-2" ]) } final class AWSResourceAccessManager: AWSNamedService, SubService { let name = "AWS Resource Access Manager" let ids = Set([ "ram-af-south-1", "ram-ap-east-1", "ram-ap-east-2", "ram-ap-northeast-1", "ram-ap-northeast-2", "ram-ap-northeast-3", "ram-ap-south-1", "ram-ap-south-2", "ram-ap-southeast-1", "ram-ap-southeast-2", "ram-ap-southeast-3", "ram-ap-southeast-4", "ram-ap-southeast-5", "ram-ap-southeast-6", "ram-ap-southeast-7", "ram-ca-central-1", "ram-ca-west-1", "ram-eu-central-1", "ram-eu-central-2", "ram-eu-north-1", "ram-eu-south-1", "ram-eu-south-2", "ram-eu-west-1", "ram-eu-west-2", "ram-eu-west-3", "ram-il-central-1", "ram-me-central-1", "ram-me-south-1", "ram-mx-central-1", "ram-sa-east-1", "ram-us-east-1", "ram-us-east-2", "ram-us-gov-east-1", "ram-us-gov-west-1", "ram-us-west-1", "ram-us-west-2" ]) } final class AWSResourceExplorer: AWSNamedService, SubService { let name = "AWS Resource Explorer" let ids = Set([ "resourceexplorer-af-south-1", "resourceexplorer-ap-east-1", "resourceexplorer-ap-east-2", "resourceexplorer-ap-northeast-1", "resourceexplorer-ap-northeast-2", "resourceexplorer-ap-northeast-3", "resourceexplorer-ap-south-1", "resourceexplorer-ap-south-2", "resourceexplorer-ap-southeast-1", "resourceexplorer-ap-southeast-2", "resourceexplorer-ap-southeast-3", "resourceexplorer-ap-southeast-4", "resourceexplorer-ap-southeast-5", "resourceexplorer-ap-southeast-6", "resourceexplorer-ap-southeast-7", "resourceexplorer-ca-central-1", "resourceexplorer-ca-west-1", "resourceexplorer-eu-central-1", "resourceexplorer-eu-central-2", "resourceexplorer-eu-north-1", "resourceexplorer-eu-south-1", "resourceexplorer-eu-south-2", "resourceexplorer-eu-west-1", "resourceexplorer-eu-west-2", "resourceexplorer-eu-west-3", "resourceexplorer-il-central-1", "resourceexplorer-me-central-1", "resourceexplorer-me-south-1", "resourceexplorer-mx-central-1", "resourceexplorer-sa-east-1", "resourceexplorer-us-east-1", "resourceexplorer-us-east-2", "resourceexplorer-us-west-1", "resourceexplorer-us-west-2" ]) } final class AWSResourceGroups: AWSNamedService, SubService { let name = "AWS Resource Groups" let ids = Set([ "resourcegroups-af-south-1", "resourcegroups-ap-east-1", "resourcegroups-ap-east-2", "resourcegroups-ap-northeast-1", "resourcegroups-ap-northeast-2", "resourcegroups-ap-northeast-3", "resourcegroups-ap-south-1", "resourcegroups-ap-south-2", "resourcegroups-ap-southeast-1", "resourcegroups-ap-southeast-2", "resourcegroups-ap-southeast-3", "resourcegroups-ap-southeast-4", "resourcegroups-ap-southeast-5", "resourcegroups-ap-southeast-6", "resourcegroups-ap-southeast-7", "resourcegroups-ca-central-1", "resourcegroups-ca-west-1", "resourcegroups-eu-central-1", "resourcegroups-eu-central-2", "resourcegroups-eu-north-1", "resourcegroups-eu-south-1", "resourcegroups-eu-south-2", "resourcegroups-eu-west-1", "resourcegroups-eu-west-2", "resourcegroups-eu-west-3", "resourcegroups-il-central-1", "resourcegroups-me-central-1", "resourcegroups-me-south-1", "resourcegroups-mx-central-1", "resourcegroups-sa-east-1", "resourcegroups-us-east-1", "resourcegroups-us-east-2", "resourcegroups-us-gov-east-1", "resourcegroups-us-gov-west-1", "resourcegroups-us-west-1", "resourcegroups-us-west-2" ]) } final class AWSResourceGroupsTaggingAPI: AWSNamedService, SubService { let name = "AWS Resource Groups Tagging API" let ids = Set([ "resourcegroupstaggingapi-af-south-1", "resourcegroupstaggingapi-ap-east-1", "resourcegroupstaggingapi-ap-east-2", "resourcegroupstaggingapi-ap-northeast-1", "resourcegroupstaggingapi-ap-northeast-2", "resourcegroupstaggingapi-ap-northeast-3", "resourcegroupstaggingapi-ap-south-1", "resourcegroupstaggingapi-ap-south-2", "resourcegroupstaggingapi-ap-southeast-1", "resourcegroupstaggingapi-ap-southeast-2", "resourcegroupstaggingapi-ap-southeast-3", "resourcegroupstaggingapi-ap-southeast-4", "resourcegroupstaggingapi-ap-southeast-5", "resourcegroupstaggingapi-ap-southeast-6", "resourcegroupstaggingapi-ap-southeast-7", "resourcegroupstaggingapi-ca-central-1", "resourcegroupstaggingapi-ca-west-1", "resourcegroupstaggingapi-eu-central-1", "resourcegroupstaggingapi-eu-central-2", "resourcegroupstaggingapi-eu-north-1", "resourcegroupstaggingapi-eu-south-1", "resourcegroupstaggingapi-eu-south-2", "resourcegroupstaggingapi-eu-west-1", "resourcegroupstaggingapi-eu-west-2", "resourcegroupstaggingapi-eu-west-3", "resourcegroupstaggingapi-il-central-1", "resourcegroupstaggingapi-me-central-1", "resourcegroupstaggingapi-me-south-1", "resourcegroupstaggingapi-mx-central-1", "resourcegroupstaggingapi-sa-east-1", "resourcegroupstaggingapi-us-east-1", "resourcegroupstaggingapi-us-east-2", "resourcegroupstaggingapi-us-gov-east-1", "resourcegroupstaggingapi-us-gov-west-1", "resourcegroupstaggingapi-us-west-1", "resourcegroupstaggingapi-us-west-2" ]) } final class AWSSecretsManager: AWSNamedService, SubService { let name = "AWS Secrets Manager" let ids = Set([ "secretsmanager-af-south-1", "secretsmanager-ap-east-1", "secretsmanager-ap-east-2", "secretsmanager-ap-northeast-1", "secretsmanager-ap-northeast-2", "secretsmanager-ap-northeast-3", "secretsmanager-ap-south-1", "secretsmanager-ap-south-2", "secretsmanager-ap-southeast-1", "secretsmanager-ap-southeast-2", "secretsmanager-ap-southeast-3", "secretsmanager-ap-southeast-4", "secretsmanager-ap-southeast-5", "secretsmanager-ap-southeast-6", "secretsmanager-ap-southeast-7", "secretsmanager-ca-central-1", "secretsmanager-ca-west-1", "secretsmanager-eu-central-1", "secretsmanager-eu-central-2", "secretsmanager-eu-north-1", "secretsmanager-eu-south-1", "secretsmanager-eu-south-2", "secretsmanager-eu-west-1", "secretsmanager-eu-west-2", "secretsmanager-eu-west-3", "secretsmanager-il-central-1", "secretsmanager-me-central-1", "secretsmanager-me-south-1", "secretsmanager-mx-central-1", "secretsmanager-sa-east-1", "secretsmanager-us-east-1", "secretsmanager-us-east-2", "secretsmanager-us-gov-east-1", "secretsmanager-us-gov-west-1", "secretsmanager-us-west-1", "secretsmanager-us-west-2" ]) } final class AWSSecurityHub: AWSNamedService, SubService { let name = "AWS Security Hub" let ids = Set([ "securityhub-af-south-1", "securityhub-ap-east-1", "securityhub-ap-east-2", "securityhub-ap-northeast-1", "securityhub-ap-northeast-2", "securityhub-ap-northeast-3", "securityhub-ap-south-1", "securityhub-ap-south-2", "securityhub-ap-southeast-1", "securityhub-ap-southeast-2", "securityhub-ap-southeast-3", "securityhub-ap-southeast-4", "securityhub-ap-southeast-5", "securityhub-ap-southeast-6", "securityhub-ap-southeast-7", "securityhub-ca-central-1", "securityhub-ca-west-1", "securityhub-eu-central-1", "securityhub-eu-central-2", "securityhub-eu-north-1", "securityhub-eu-south-1", "securityhub-eu-south-2", "securityhub-eu-west-1", "securityhub-eu-west-2", "securityhub-eu-west-3", "securityhub-il-central-1", "securityhub-me-central-1", "securityhub-me-south-1", "securityhub-mx-central-1", "securityhub-sa-east-1", "securityhub-us-east-1", "securityhub-us-east-2", "securityhub-us-gov-east-1", "securityhub-us-gov-west-1", "securityhub-us-west-1", "securityhub-us-west-2" ]) } final class AWSSecurityIncidentResponse: AWSNamedService, SubService { let name = "AWS Security Incident Response" let ids = Set([ "security-ir-af-south-1", "security-ir-ap-east-1", "security-ir-ap-northeast-1", "security-ir-ap-northeast-2", "security-ir-ap-south-1", "security-ir-ap-south-2", "security-ir-ap-southeast-1", "security-ir-ap-southeast-2", "security-ir-ap-southeast-3", "security-ir-ap-southeast-4", "security-ir-ca-central-1", "security-ir-eu-central-1", "security-ir-eu-central-2", "security-ir-eu-north-1", "security-ir-eu-south-1", "security-ir-eu-south-2", "security-ir-eu-west-1", "security-ir-eu-west-2", "security-ir-eu-west-3", "security-ir-me-central-1", "security-ir-me-south-1", "security-ir-sa-east-1", "security-ir-us-east-1", "security-ir-us-east-2", "security-ir-us-west-2" ]) } final class AWSSecurityTokenService: AWSNamedService, SubService { let name = "AWS Security Token Service" let ids = Set([ "sts-af-south-1", "sts-ap-east-1", "sts-ap-east-2", "sts-ap-northeast-1", "sts-ap-northeast-2", "sts-ap-northeast-3", "sts-ap-south-1", "sts-ap-south-2", "sts-ap-southeast-1", "sts-ap-southeast-2", "sts-ap-southeast-3", "sts-ap-southeast-4", "sts-ap-southeast-5", "sts-ap-southeast-6", "sts-ap-southeast-7", "sts-ca-central-1", "sts-ca-west-1", "sts-eu-central-1", "sts-eu-central-2", "sts-eu-north-1", "sts-eu-south-1", "sts-eu-south-2", "sts-eu-west-1", "sts-eu-west-2", "sts-eu-west-3", "sts-il-central-1", "sts-me-central-1", "sts-me-south-1", "sts-mx-central-1", "sts-sa-east-1", "sts-us-east-1", "sts-us-east-2", "sts-us-gov-east-1", "sts-us-gov-west-1", "sts-us-west-1", "sts-us-west-2" ]) } final class AWSServerlessApplicationRepository: AWSNamedService, SubService { let name = "AWS Serverless Application Repository" let ids = Set([ "serverlessrepo-ap-east-1", "serverlessrepo-ap-northeast-1", "serverlessrepo-ap-northeast-2", "serverlessrepo-ap-south-1", "serverlessrepo-ap-southeast-1", "serverlessrepo-ap-southeast-2", "serverlessrepo-ca-central-1", "serverlessrepo-eu-central-1", "serverlessrepo-eu-north-1", "serverlessrepo-eu-west-1", "serverlessrepo-eu-west-2", "serverlessrepo-eu-west-3", "serverlessrepo-me-south-1", "serverlessrepo-sa-east-1", "serverlessrepo-us-east-1", "serverlessrepo-us-east-2", "serverlessrepo-us-gov-east-1", "serverlessrepo-us-gov-west-1", "serverlessrepo-us-west-1", "serverlessrepo-us-west-2" ]) } final class AWSServiceCatalog: AWSNamedService, SubService { let name = "AWS Service Catalog" let ids = Set([ "servicecatalog-af-south-1", "servicecatalog-ap-east-1", "servicecatalog-ap-northeast-1", "servicecatalog-ap-northeast-2", "servicecatalog-ap-northeast-3", "servicecatalog-ap-south-1", "servicecatalog-ap-south-2", "servicecatalog-ap-southeast-1", "servicecatalog-ap-southeast-2", "servicecatalog-ap-southeast-3", "servicecatalog-ap-southeast-4", "servicecatalog-ca-central-1", "servicecatalog-eu-central-1", "servicecatalog-eu-central-2", "servicecatalog-eu-north-1", "servicecatalog-eu-south-1", "servicecatalog-eu-south-2", "servicecatalog-eu-west-1", "servicecatalog-eu-west-2", "servicecatalog-eu-west-3", "servicecatalog-il-central-1", "servicecatalog-me-central-1", "servicecatalog-me-south-1", "servicecatalog-sa-east-1", "servicecatalog-us-east-1", "servicecatalog-us-east-2", "servicecatalog-us-gov-east-1", "servicecatalog-us-gov-west-1", "servicecatalog-us-west-1", "servicecatalog-us-west-2" ]) } final class AWSServiceQuotas: AWSNamedService, SubService { let name = "AWS Service Quotas" let ids = Set([ "servicequotas-af-south-1", "servicequotas-ap-east-1", "servicequotas-ap-east-2", "servicequotas-ap-northeast-1", "servicequotas-ap-northeast-2", "servicequotas-ap-northeast-3", "servicequotas-ap-south-1", "servicequotas-ap-south-2", "servicequotas-ap-southeast-1", "servicequotas-ap-southeast-2", "servicequotas-ap-southeast-3", "servicequotas-ap-southeast-4", "servicequotas-ap-southeast-5", "servicequotas-ap-southeast-6", "servicequotas-ap-southeast-7", "servicequotas-ca-central-1", "servicequotas-ca-west-1", "servicequotas-eu-central-1", "servicequotas-eu-central-2", "servicequotas-eu-north-1", "servicequotas-eu-south-1", "servicequotas-eu-south-2", "servicequotas-eu-west-1", "servicequotas-eu-west-2", "servicequotas-eu-west-3", "servicequotas-il-central-1", "servicequotas-me-central-1", "servicequotas-me-south-1", "servicequotas-mx-central-1", "servicequotas-sa-east-1", "servicequotas-us-east-1", "servicequotas-us-east-2", "servicequotas-us-gov-east-1", "servicequotas-us-gov-west-1", "servicequotas-us-west-1", "servicequotas-us-west-2" ]) } final class AWSSignUp: AWSNamedService, SubService { let name = "AWS Sign Up" let ids = Set([ "signup" ]) } final class AWSSignIn: AWSNamedService, SubService { let name = "AWS Sign-In" let ids = Set([ "signin-af-south-1", "signin-ap-east-1", "signin-ap-east-2", "signin-ap-northeast-1", "signin-ap-northeast-2", "signin-ap-northeast-3", "signin-ap-south-1", "signin-ap-south-2", "signin-ap-southeast-1", "signin-ap-southeast-2", "signin-ap-southeast-3", "signin-ap-southeast-4", "signin-ap-southeast-5", "signin-ap-southeast-6", "signin-ap-southeast-7", "signin-ca-central-1", "signin-ca-west-1", "signin-eu-central-1", "signin-eu-central-2", "signin-eu-north-1", "signin-eu-south-1", "signin-eu-south-2", "signin-eu-west-1", "signin-eu-west-2", "signin-eu-west-3", "signin-il-central-1", "signin-me-central-1", "signin-me-south-1", "signin-mx-central-1", "signin-sa-east-1", "signin-us-east-1", "signin-us-east-2", "signin-us-gov-east-1", "signin-us-gov-west-1", "signin-us-west-1", "signin-us-west-2" ]) } final class AWSSimSpaceWeaver: AWSNamedService, SubService { let name = "AWS SimSpace Weaver" let ids = Set([ "simspaceweaver-ap-southeast-1", "simspaceweaver-ap-southeast-2", "simspaceweaver-eu-central-1", "simspaceweaver-eu-north-1", "simspaceweaver-eu-west-1", "simspaceweaver-us-east-1", "simspaceweaver-us-east-2", "simspaceweaver-us-gov-east-1", "simspaceweaver-us-gov-west-1", "simspaceweaver-us-west-2" ]) } final class AWSSitetoSiteVPN: AWSNamedService, SubService { let name = "AWS Site-to-Site VPN" let ids = Set([ "vpnvpc-af-south-1", "vpnvpc-ap-east-1", "vpnvpc-ap-east-2", "vpnvpc-ap-northeast-1", "vpnvpc-ap-northeast-2", "vpnvpc-ap-northeast-3", "vpnvpc-ap-south-1", "vpnvpc-ap-south-2", "vpnvpc-ap-southeast-1", "vpnvpc-ap-southeast-2", "vpnvpc-ap-southeast-3", "vpnvpc-ap-southeast-4", "vpnvpc-ap-southeast-5", "vpnvpc-ap-southeast-6", "vpnvpc-ap-southeast-7", "vpnvpc-ca-central-1", "vpnvpc-ca-west-1", "vpnvpc-eu-central-1", "vpnvpc-eu-central-2", "vpnvpc-eu-north-1", "vpnvpc-eu-south-1", "vpnvpc-eu-south-2", "vpnvpc-eu-west-1", "vpnvpc-eu-west-2", "vpnvpc-eu-west-3", "vpnvpc-il-central-1", "vpnvpc-me-central-1", "vpnvpc-me-south-1", "vpnvpc-mx-central-1", "vpnvpc-sa-east-1", "vpnvpc-us-east-1", "vpnvpc-us-east-2", "vpnvpc-us-gov-east-1", "vpnvpc-us-gov-west-1", "vpnvpc-us-west-1", "vpnvpc-us-west-2" ]) } final class AWSStepFunctions: AWSNamedService, SubService { let name = "AWS Step Functions" let ids = Set([ "state-af-south-1", "state-ap-east-1", "state-ap-east-2", "state-ap-northeast-1", "state-ap-northeast-2", "state-ap-northeast-3", "state-ap-south-1", "state-ap-south-2", "state-ap-southeast-1", "state-ap-southeast-2", "state-ap-southeast-3", "state-ap-southeast-4", "state-ap-southeast-5", "state-ap-southeast-6", "state-ap-southeast-7", "state-ca-central-1", "state-ca-west-1", "state-eu-central-1", "state-eu-central-2", "state-eu-north-1", "state-eu-south-1", "state-eu-south-2", "state-eu-west-1", "state-eu-west-2", "state-eu-west-3", "state-il-central-1", "state-me-central-1", "state-me-south-1", "state-mx-central-1", "state-sa-east-1", "state-us-east-1", "state-us-east-2", "state-us-gov-east-1", "state-us-gov-west-1", "state-us-west-1", "state-us-west-2" ]) } final class AWSStorageGateway: AWSNamedService, SubService { let name = "AWS Storage Gateway" let ids = Set([ "storagegateway-af-south-1", "storagegateway-ap-east-1", "storagegateway-ap-east-2", "storagegateway-ap-northeast-1", "storagegateway-ap-northeast-2", "storagegateway-ap-northeast-3", "storagegateway-ap-south-1", "storagegateway-ap-south-2", "storagegateway-ap-southeast-1", "storagegateway-ap-southeast-2", "storagegateway-ap-southeast-3", "storagegateway-ap-southeast-4", "storagegateway-ap-southeast-5", "storagegateway-ap-southeast-6", "storagegateway-ap-southeast-7", "storagegateway-ca-central-1", "storagegateway-ca-west-1", "storagegateway-eu-central-1", "storagegateway-eu-central-2", "storagegateway-eu-north-1", "storagegateway-eu-south-1", "storagegateway-eu-south-2", "storagegateway-eu-west-1", "storagegateway-eu-west-2", "storagegateway-eu-west-3", "storagegateway-il-central-1", "storagegateway-me-central-1", "storagegateway-me-south-1", "storagegateway-mx-central-1", "storagegateway-sa-east-1", "storagegateway-us-east-1", "storagegateway-us-east-2", "storagegateway-us-gov-east-1", "storagegateway-us-gov-west-1", "storagegateway-us-west-1", "storagegateway-us-west-2" ]) } final class AWSSupportAPI: AWSNamedService, SubService { let name = "AWS Support API" let ids = Set([ "supportapi", "supportapi-us-gov-east-1", "supportapi-us-gov-west-1" ]) } final class AWSSupportCenter: AWSNamedService, SubService { let name = "AWS Support Center" let ids = Set([ "supportcenter", "supportcenter-us-gov-west-1" ]) } final class AWSSystemsManager: AWSNamedService, SubService { let name = "AWS Systems Manager" let ids = Set([ "ec2systemsmanager-af-south-1", "ec2systemsmanager-ap-east-1", "ec2systemsmanager-ap-east-2", "ec2systemsmanager-ap-northeast-1", "ec2systemsmanager-ap-northeast-2", "ec2systemsmanager-ap-northeast-3", "ec2systemsmanager-ap-south-1", "ec2systemsmanager-ap-south-2", "ec2systemsmanager-ap-southeast-1", "ec2systemsmanager-ap-southeast-2", "ec2systemsmanager-ap-southeast-3", "ec2systemsmanager-ap-southeast-4", "ec2systemsmanager-ap-southeast-5", "ec2systemsmanager-ap-southeast-6", "ec2systemsmanager-ap-southeast-7", "ec2systemsmanager-ca-central-1", "ec2systemsmanager-ca-west-1", "ec2systemsmanager-eu-central-1", "ec2systemsmanager-eu-central-2", "ec2systemsmanager-eu-north-1", "ec2systemsmanager-eu-south-1", "ec2systemsmanager-eu-south-2", "ec2systemsmanager-eu-west-1", "ec2systemsmanager-eu-west-2", "ec2systemsmanager-eu-west-3", "ec2systemsmanager-il-central-1", "ec2systemsmanager-me-central-1", "ec2systemsmanager-me-south-1", "ec2systemsmanager-mx-central-1", "ec2systemsmanager-sa-east-1", "ec2systemsmanager-us-east-1", "ec2systemsmanager-us-east-2", "ec2systemsmanager-us-gov-east-1", "ec2systemsmanager-us-gov-west-1", "ec2systemsmanager-us-west-1", "ec2systemsmanager-us-west-2" ]) } final class AWSSystemsManagerForSAP: AWSNamedService, SubService { let name = "AWS Systems Manager for SAP" let ids = Set([ "ssmsap-af-south-1", "ssmsap-ap-east-1", "ssmsap-ap-northeast-1", "ssmsap-ap-northeast-2", "ssmsap-ap-northeast-3", "ssmsap-ap-south-1", "ssmsap-ap-south-2", "ssmsap-ap-southeast-1", "ssmsap-ap-southeast-2", "ssmsap-ap-southeast-3", "ssmsap-ap-southeast-4", "ssmsap-ca-central-1", "ssmsap-eu-central-1", "ssmsap-eu-central-2", "ssmsap-eu-north-1", "ssmsap-eu-south-1", "ssmsap-eu-south-2", "ssmsap-eu-west-1", "ssmsap-eu-west-2", "ssmsap-eu-west-3", "ssmsap-il-central-1", "ssmsap-me-central-1", "ssmsap-me-south-1", "ssmsap-sa-east-1", "ssmsap-us-east-1", "ssmsap-us-east-2", "ssmsap-us-west-1", "ssmsap-us-west-2" ]) } final class AWSTelcoNetworkBuilder: AWSNamedService, SubService { let name = "AWS Telco Network Builder" let ids = Set([ "tnb-ap-northeast-2", "tnb-ap-southeast-2", "tnb-ca-central-1", "tnb-eu-central-1", "tnb-eu-north-1", "tnb-eu-south-2", "tnb-eu-west-3", "tnb-sa-east-1", "tnb-us-east-1", "tnb-us-west-2" ]) } final class AWSTrafficMirroring: AWSNamedService, SubService { let name = "AWS Traffic Mirroring" let ids = Set([ "trafficmirroring-af-south-1", "trafficmirroring-ap-east-1", "trafficmirroring-ap-east-2", "trafficmirroring-ap-northeast-1", "trafficmirroring-ap-northeast-2", "trafficmirroring-ap-northeast-3", "trafficmirroring-ap-south-1", "trafficmirroring-ap-south-2", "trafficmirroring-ap-southeast-1", "trafficmirroring-ap-southeast-2", "trafficmirroring-ap-southeast-3", "trafficmirroring-ap-southeast-4", "trafficmirroring-ap-southeast-5", "trafficmirroring-ap-southeast-6", "trafficmirroring-ap-southeast-7", "trafficmirroring-ca-central-1", "trafficmirroring-ca-west-1", "trafficmirroring-eu-central-1", "trafficmirroring-eu-central-2", "trafficmirroring-eu-north-1", "trafficmirroring-eu-south-1", "trafficmirroring-eu-south-2", "trafficmirroring-eu-west-1", "trafficmirroring-eu-west-2", "trafficmirroring-eu-west-3", "trafficmirroring-il-central-1", "trafficmirroring-me-central-1", "trafficmirroring-me-south-1", "trafficmirroring-mx-central-1", "trafficmirroring-sa-east-1", "trafficmirroring-us-east-1", "trafficmirroring-us-east-2", "trafficmirroring-us-gov-east-1", "trafficmirroring-us-gov-west-1", "trafficmirroring-us-west-1", "trafficmirroring-us-west-2" ]) } final class AWSTransferFamily: AWSNamedService, SubService { let name = "AWS Transfer Family" let ids = Set([ "transfer-af-south-1", "transfer-ap-east-1", "transfer-ap-east-2", "transfer-ap-northeast-1", "transfer-ap-northeast-2", "transfer-ap-northeast-3", "transfer-ap-south-1", "transfer-ap-south-2", "transfer-ap-southeast-1", "transfer-ap-southeast-2", "transfer-ap-southeast-3", "transfer-ap-southeast-4", "transfer-ap-southeast-5", "transfer-ap-southeast-6", "transfer-ap-southeast-7", "transfer-ca-central-1", "transfer-ca-west-1", "transfer-eu-central-1", "transfer-eu-central-2", "transfer-eu-north-1", "transfer-eu-south-1", "transfer-eu-south-2", "transfer-eu-west-1", "transfer-eu-west-2", "transfer-eu-west-3", "transfer-il-central-1", "transfer-me-central-1", "transfer-me-south-1", "transfer-mx-central-1", "transfer-sa-east-1", "transfer-us-east-1", "transfer-us-east-2", "transfer-us-gov-east-1", "transfer-us-gov-west-1", "transfer-us-west-1", "transfer-us-west-2" ]) } final class AWSTransform: AWSNamedService, SubService { let name = "AWS Transform" let ids = Set([ "transform-ap-northeast-1", "transform-ap-northeast-2", "transform-ap-south-1", "transform-ap-southeast-2", "transform-ca-central-1", "transform-eu-central-1", "transform-eu-west-2", "transform-us-east-1" ]) } final class AWSTransitGateway: AWSNamedService, SubService { let name = "AWS Transit Gateway" let ids = Set([ "transitgateway-af-south-1", "transitgateway-ap-east-1", "transitgateway-ap-east-2", "transitgateway-ap-northeast-1", "transitgateway-ap-northeast-2", "transitgateway-ap-northeast-3", "transitgateway-ap-south-1", "transitgateway-ap-south-2", "transitgateway-ap-southeast-1", "transitgateway-ap-southeast-2", "transitgateway-ap-southeast-3", "transitgateway-ap-southeast-4", "transitgateway-ap-southeast-5", "transitgateway-ap-southeast-6", "transitgateway-ap-southeast-7", "transitgateway-ca-central-1", "transitgateway-ca-west-1", "transitgateway-eu-central-1", "transitgateway-eu-central-2", "transitgateway-eu-north-1", "transitgateway-eu-south-1", "transitgateway-eu-south-2", "transitgateway-eu-west-1", "transitgateway-eu-west-2", "transitgateway-eu-west-3", "transitgateway-il-central-1", "transitgateway-me-central-1", "transitgateway-me-south-1", "transitgateway-mx-central-1", "transitgateway-sa-east-1", "transitgateway-us-east-1", "transitgateway-us-east-2", "transitgateway-us-gov-east-1", "transitgateway-us-gov-west-1", "transitgateway-us-west-1", "transitgateway-us-west-2" ]) } final class AWSTrustedAdvisor: AWSNamedService, SubService { let name = "AWS Trusted Advisor" let ids = Set([ "trustedadvisor", "trustedadvisor-us-gov-east-1", "trustedadvisor-us-gov-west-1" ]) } final class AWSUserNotifications: AWSNamedService, SubService { let name = "AWS User Notifications" let ids = Set([ "notifications" ]) } final class AWSVMImportExport: AWSNamedService, SubService { let name = "AWS VM Import/Export" let ids = Set([ "vmimportexport-af-south-1", "vmimportexport-ap-east-1", "vmimportexport-ap-east-2", "vmimportexport-ap-northeast-1", "vmimportexport-ap-northeast-2", "vmimportexport-ap-northeast-3", "vmimportexport-ap-south-1", "vmimportexport-ap-south-2", "vmimportexport-ap-southeast-1", "vmimportexport-ap-southeast-2", "vmimportexport-ap-southeast-3", "vmimportexport-ap-southeast-4", "vmimportexport-ap-southeast-5", "vmimportexport-ap-southeast-6", "vmimportexport-ap-southeast-7", "vmimportexport-ca-central-1", "vmimportexport-ca-west-1", "vmimportexport-eu-central-1", "vmimportexport-eu-central-2", "vmimportexport-eu-north-1", "vmimportexport-eu-south-1", "vmimportexport-eu-south-2", "vmimportexport-eu-west-1", "vmimportexport-eu-west-2", "vmimportexport-eu-west-3", "vmimportexport-il-central-1", "vmimportexport-me-central-1", "vmimportexport-me-south-1", "vmimportexport-mx-central-1", "vmimportexport-sa-east-1", "vmimportexport-us-east-1", "vmimportexport-us-east-2", "vmimportexport-us-gov-east-1", "vmimportexport-us-gov-west-1", "vmimportexport-us-west-1", "vmimportexport-us-west-2" ]) } final class AWSVPCEPrivateLink: AWSNamedService, SubService { let name = "AWS VPCE PrivateLink" let ids = Set([ "privatelink-af-south-1", "privatelink-ap-east-1", "privatelink-ap-east-2", "privatelink-ap-northeast-1", "privatelink-ap-northeast-2", "privatelink-ap-northeast-3", "privatelink-ap-south-1", "privatelink-ap-south-2", "privatelink-ap-southeast-1", "privatelink-ap-southeast-2", "privatelink-ap-southeast-3", "privatelink-ap-southeast-4", "privatelink-ap-southeast-5", "privatelink-ap-southeast-6", "privatelink-ap-southeast-7", "privatelink-ca-central-1", "privatelink-ca-west-1", "privatelink-eu-central-1", "privatelink-eu-central-2", "privatelink-eu-north-1", "privatelink-eu-south-1", "privatelink-eu-south-2", "privatelink-eu-west-1", "privatelink-eu-west-2", "privatelink-eu-west-3", "privatelink-il-central-1", "privatelink-me-central-1", "privatelink-me-south-1", "privatelink-mx-central-1", "privatelink-sa-east-1", "privatelink-us-east-1", "privatelink-us-east-2", "privatelink-us-gov-east-1", "privatelink-us-gov-west-1", "privatelink-us-west-1", "privatelink-us-west-2" ]) } final class AWSVerifiedAccess: AWSNamedService, SubService { let name = "AWS Verified Access" let ids = Set([ "verifiedaccess-ap-northeast-1", "verifiedaccess-ap-northeast-2", "verifiedaccess-ap-south-1", "verifiedaccess-ap-southeast-1", "verifiedaccess-ap-southeast-2", "verifiedaccess-ap-southeast-3", "verifiedaccess-ca-central-1", "verifiedaccess-eu-central-1", "verifiedaccess-eu-north-1", "verifiedaccess-eu-south-1", "verifiedaccess-eu-west-1", "verifiedaccess-eu-west-2", "verifiedaccess-il-central-1", "verifiedaccess-sa-east-1", "verifiedaccess-us-east-1", "verifiedaccess-us-east-2", "verifiedaccess-us-gov-east-1", "verifiedaccess-us-gov-west-1", "verifiedaccess-us-west-1", "verifiedaccess-us-west-2" ]) } final class AWSWAF: AWSNamedService, SubService { let name = "AWS WAF" let ids = Set([ "awswaf-af-south-1", "awswaf-ap-east-1", "awswaf-ap-east-2", "awswaf-ap-northeast-1", "awswaf-ap-northeast-2", "awswaf-ap-northeast-3", "awswaf-ap-south-1", "awswaf-ap-south-2", "awswaf-ap-southeast-1", "awswaf-ap-southeast-2", "awswaf-ap-southeast-3", "awswaf-ap-southeast-4", "awswaf-ap-southeast-5", "awswaf-ap-southeast-6", "awswaf-ap-southeast-7", "awswaf-ca-central-1", "awswaf-ca-west-1", "awswaf-eu-central-1", "awswaf-eu-central-2", "awswaf-eu-north-1", "awswaf-eu-south-1", "awswaf-eu-south-2", "awswaf-eu-west-1", "awswaf-eu-west-2", "awswaf-eu-west-3", "awswaf-il-central-1", "awswaf-me-central-1", "awswaf-me-south-1", "awswaf-mx-central-1", "awswaf-sa-east-1", "awswaf-us-east-1", "awswaf-us-east-2", "awswaf-us-gov-east-1", "awswaf-us-gov-west-1", "awswaf-us-west-1", "awswaf-us-west-2" ]) } final class AWSWellArchitectedTool: AWSNamedService, SubService { let name = "AWS Well-Architected Tool" let ids = Set([ "wellarchitected-ap-east-1", "wellarchitected-ap-northeast-1", "wellarchitected-ap-northeast-2", "wellarchitected-ap-south-1", "wellarchitected-ap-southeast-1", "wellarchitected-ap-southeast-2", "wellarchitected-ca-central-1", "wellarchitected-eu-central-1", "wellarchitected-eu-north-1", "wellarchitected-eu-west-1", "wellarchitected-eu-west-2", "wellarchitected-eu-west-3", "wellarchitected-me-south-1", "wellarchitected-sa-east-1", "wellarchitected-us-east-1", "wellarchitected-us-east-2", "wellarchitected-us-gov-east-1", "wellarchitected-us-gov-west-1", "wellarchitected-us-west-1", "wellarchitected-us-west-2" ]) } final class AWSWickr: AWSNamedService, SubService { let name = "AWS Wickr" let ids = Set([ "wickr-ap-northeast-1", "wickr-ap-southeast-1", "wickr-ap-southeast-2", "wickr-ap-southeast-5", "wickr-ca-central-1", "wickr-eu-central-1", "wickr-eu-central-2", "wickr-eu-north-1", "wickr-eu-west-2", "wickr-us-east-1", "wickr-us-gov-west-1" ]) } final class AWSXRay: AWSNamedService, SubService { let name = "AWS X-Ray" let ids = Set([ "xray-af-south-1", "xray-ap-east-1", "xray-ap-east-2", "xray-ap-northeast-1", "xray-ap-northeast-2", "xray-ap-northeast-3", "xray-ap-south-1", "xray-ap-south-2", "xray-ap-southeast-1", "xray-ap-southeast-2", "xray-ap-southeast-3", "xray-ap-southeast-4", "xray-ap-southeast-5", "xray-ap-southeast-6", "xray-ap-southeast-7", "xray-ca-central-1", "xray-ca-west-1", "xray-eu-central-1", "xray-eu-central-2", "xray-eu-north-1", "xray-eu-south-1", "xray-eu-south-2", "xray-eu-west-1", "xray-eu-west-2", "xray-eu-west-3", "xray-il-central-1", "xray-me-central-1", "xray-me-south-1", "xray-mx-central-1", "xray-sa-east-1", "xray-us-east-1", "xray-us-east-2", "xray-us-gov-east-1", "xray-us-gov-west-1", "xray-us-west-1", "xray-us-west-2" ]) } final class AWSRePostPrivate: AWSNamedService, SubService { let name = "AWS re:Post Private" let ids = Set([ "repostspace-ap-southeast-1", "repostspace-ap-southeast-2", "repostspace-ca-central-1", "repostspace-eu-central-1", "repostspace-eu-west-1", "repostspace-us-east-1", "repostspace-us-west-2" ]) } final class AmazonAPIGateway: AWSNamedService, SubService { let name = "Amazon API Gateway" let ids = Set([ "apigateway-af-south-1", "apigateway-ap-east-1", "apigateway-ap-east-2", "apigateway-ap-northeast-1", "apigateway-ap-northeast-2", "apigateway-ap-northeast-3", "apigateway-ap-south-1", "apigateway-ap-south-2", "apigateway-ap-southeast-1", "apigateway-ap-southeast-2", "apigateway-ap-southeast-3", "apigateway-ap-southeast-4", "apigateway-ap-southeast-5", "apigateway-ap-southeast-6", "apigateway-ap-southeast-7", "apigateway-ca-central-1", "apigateway-ca-west-1", "apigateway-eu-central-1", "apigateway-eu-central-2", "apigateway-eu-north-1", "apigateway-eu-south-1", "apigateway-eu-south-2", "apigateway-eu-west-1", "apigateway-eu-west-2", "apigateway-eu-west-3", "apigateway-il-central-1", "apigateway-me-central-1", "apigateway-me-south-1", "apigateway-mx-central-1", "apigateway-sa-east-1", "apigateway-us-east-1", "apigateway-us-east-2", "apigateway-us-gov-east-1", "apigateway-us-gov-west-1", "apigateway-us-west-1", "apigateway-us-west-2" ]) } final class AmazonAppFlow: AWSNamedService, SubService { let name = "Amazon AppFlow" let ids = Set([ "appflow-af-south-1", "appflow-ap-northeast-1", "appflow-ap-northeast-2", "appflow-ap-south-1", "appflow-ap-southeast-1", "appflow-ap-southeast-2", "appflow-ca-central-1", "appflow-eu-central-1", "appflow-eu-west-1", "appflow-eu-west-2", "appflow-eu-west-3", "appflow-sa-east-1", "appflow-us-east-1", "appflow-us-east-2", "appflow-us-west-1", "appflow-us-west-2" ]) } final class AmazonAthena: AWSNamedService, SubService { let name = "Amazon Athena" let ids = Set([ "athena-af-south-1", "athena-ap-east-1", "athena-ap-east-2", "athena-ap-northeast-1", "athena-ap-northeast-2", "athena-ap-northeast-3", "athena-ap-south-1", "athena-ap-south-2", "athena-ap-southeast-1", "athena-ap-southeast-2", "athena-ap-southeast-3", "athena-ap-southeast-4", "athena-ap-southeast-5", "athena-ap-southeast-6", "athena-ap-southeast-7", "athena-ca-central-1", "athena-ca-west-1", "athena-eu-central-1", "athena-eu-central-2", "athena-eu-north-1", "athena-eu-south-1", "athena-eu-south-2", "athena-eu-west-1", "athena-eu-west-2", "athena-eu-west-3", "athena-il-central-1", "athena-me-central-1", "athena-me-south-1", "athena-mx-central-1", "athena-sa-east-1", "athena-us-east-1", "athena-us-east-2", "athena-us-gov-east-1", "athena-us-gov-west-1", "athena-us-west-1", "athena-us-west-2" ]) } final class AmazonAugmentedAI: AWSNamedService, SubService { let name = "Amazon Augmented AI" let ids = Set([ "augmentedai-ap-northeast-1", "augmentedai-ap-northeast-2", "augmentedai-ap-south-1", "augmentedai-ap-southeast-1", "augmentedai-ap-southeast-2", "augmentedai-ca-central-1", "augmentedai-eu-central-1", "augmentedai-eu-west-1", "augmentedai-eu-west-2", "augmentedai-us-east-1", "augmentedai-us-east-2", "augmentedai-us-west-2" ]) } final class AmazonAuroraDSQLService: AWSNamedService, SubService { let name = "Amazon Aurora DSQL Service" let ids = Set([ "dsql-ap-northeast-1", "dsql-ap-northeast-2", "dsql-ap-northeast-3", "dsql-ap-southeast-2", "dsql-ap-southeast-4", "dsql-ca-central-1", "dsql-ca-west-1", "dsql-eu-central-1", "dsql-eu-west-1", "dsql-eu-west-2", "dsql-eu-west-3", "dsql-us-east-1", "dsql-us-east-2", "dsql-us-west-2" ]) } final class AmazonBedrock: AWSNamedService, SubService { let name = "Amazon Bedrock" let ids = Set([ "bedrock-af-south-1", "bedrock-ap-east-2", "bedrock-ap-northeast-1", "bedrock-ap-northeast-2", "bedrock-ap-northeast-3", "bedrock-ap-south-1", "bedrock-ap-south-2", "bedrock-ap-southeast-1", "bedrock-ap-southeast-2", "bedrock-ap-southeast-3", "bedrock-ap-southeast-4", "bedrock-ap-southeast-5", "bedrock-ap-southeast-6", "bedrock-ap-southeast-7", "bedrock-ca-central-1", "bedrock-ca-west-1", "bedrock-eu-central-1", "bedrock-eu-central-2", "bedrock-eu-north-1", "bedrock-eu-south-1", "bedrock-eu-south-2", "bedrock-eu-west-1", "bedrock-eu-west-2", "bedrock-eu-west-3", "bedrock-il-central-1", "bedrock-me-central-1", "bedrock-me-south-1", "bedrock-mx-central-1", "bedrock-sa-east-1", "bedrock-us-east-1", "bedrock-us-east-2", "bedrock-us-gov-east-1", "bedrock-us-gov-west-1", "bedrock-us-west-1", "bedrock-us-west-2" ]) } final class AmazonBraket: AWSNamedService, SubService { let name = "Amazon Braket" let ids = Set([ "braket-eu-north-1", "braket-eu-west-2", "braket-us-east-1", "braket-us-west-1", "braket-us-west-2" ]) } final class AmazonChime: AWSNamedService, SubService { let name = "Amazon Chime" let ids = Set([ "chime", "chime-us-gov-east-1", "chime-us-gov-west-1" ]) } final class AmazonCloudDirectory: AWSNamedService, SubService { let name = "Amazon Cloud Directory" let ids = Set([ "clouddirectory-ap-southeast-1", "clouddirectory-ap-southeast-2", "clouddirectory-ca-central-1", "clouddirectory-eu-central-1", "clouddirectory-eu-west-1", "clouddirectory-eu-west-2", "clouddirectory-us-east-1", "clouddirectory-us-east-2", "clouddirectory-us-gov-west-1", "clouddirectory-us-west-2" ]) } final class AmazonCloudFront: AWSNamedService, SubService { let name = "Amazon CloudFront" let ids = Set([ "cloudfront" ]) } final class AmazonCloudSearch: AWSNamedService, SubService { let name = "Amazon CloudSearch" let ids = Set([ "cloudsearch-ap-northeast-1", "cloudsearch-ap-northeast-2", "cloudsearch-ap-southeast-1", "cloudsearch-ap-southeast-2", "cloudsearch-eu-central-1", "cloudsearch-eu-west-1", "cloudsearch-sa-east-1", "cloudsearch-us-east-1", "cloudsearch-us-west-1", "cloudsearch-us-west-2" ]) } final class AmazonCloudWatch: AWSNamedService, SubService { let name = "Amazon CloudWatch" let ids = Set([ "cloudwatch-af-south-1", "cloudwatch-ap-east-1", "cloudwatch-ap-east-2", "cloudwatch-ap-northeast-1", "cloudwatch-ap-northeast-2", "cloudwatch-ap-northeast-3", "cloudwatch-ap-south-1", "cloudwatch-ap-south-2", "cloudwatch-ap-southeast-1", "cloudwatch-ap-southeast-2", "cloudwatch-ap-southeast-3", "cloudwatch-ap-southeast-4", "cloudwatch-ap-southeast-5", "cloudwatch-ap-southeast-6", "cloudwatch-ap-southeast-7", "cloudwatch-ca-central-1", "cloudwatch-ca-west-1", "cloudwatch-eu-central-1", "cloudwatch-eu-central-2", "cloudwatch-eu-north-1", "cloudwatch-eu-south-1", "cloudwatch-eu-south-2", "cloudwatch-eu-west-1", "cloudwatch-eu-west-2", "cloudwatch-eu-west-3", "cloudwatch-il-central-1", "cloudwatch-me-central-1", "cloudwatch-me-south-1", "cloudwatch-mx-central-1", "cloudwatch-sa-east-1", "cloudwatch-us-east-1", "cloudwatch-us-east-2", "cloudwatch-us-gov-east-1", "cloudwatch-us-gov-west-1", "cloudwatch-us-west-1", "cloudwatch-us-west-2" ]) } final class AmazonCloudWatchApplicationInsights: AWSNamedService, SubService { let name = "Amazon CloudWatch Application Insights" let ids = Set([ "applicationinsights-af-south-1", "applicationinsights-ap-east-1", "applicationinsights-ap-northeast-1", "applicationinsights-ap-northeast-2", "applicationinsights-ap-northeast-3", "applicationinsights-ap-south-1", "applicationinsights-ap-south-2", "applicationinsights-ap-southeast-1", "applicationinsights-ap-southeast-2", "applicationinsights-ap-southeast-3", "applicationinsights-ap-southeast-4", "applicationinsights-ca-central-1", "applicationinsights-ca-west-1", "applicationinsights-eu-central-1", "applicationinsights-eu-central-2", "applicationinsights-eu-north-1", "applicationinsights-eu-south-1", "applicationinsights-eu-south-2", "applicationinsights-eu-west-1", "applicationinsights-eu-west-2", "applicationinsights-eu-west-3", "applicationinsights-il-central-1", "applicationinsights-me-central-1", "applicationinsights-me-south-1", "applicationinsights-sa-east-1", "applicationinsights-us-east-1", "applicationinsights-us-east-2", "applicationinsights-us-gov-east-1", "applicationinsights-us-gov-west-1", "applicationinsights-us-west-1", "applicationinsights-us-west-2" ]) } final class AmazonCloudWatchEvidently: AWSNamedService, SubService { let name = "Amazon CloudWatch Evidently" let ids = Set([ "evidently-ap-northeast-1", "evidently-ap-southeast-1", "evidently-ap-southeast-2", "evidently-eu-central-1", "evidently-eu-north-1", "evidently-eu-west-1", "evidently-us-east-1", "evidently-us-east-2", "evidently-us-west-2" ]) } final class AmazonCloudWatchInternetMonitor: AWSNamedService, SubService { let name = "Amazon CloudWatch Internet Monitor" let ids = Set([ "internetmonitor-af-south-1", "internetmonitor-ap-east-1", "internetmonitor-ap-northeast-1", "internetmonitor-ap-northeast-2", "internetmonitor-ap-northeast-3", "internetmonitor-ap-south-1", "internetmonitor-ap-south-2", "internetmonitor-ap-southeast-1", "internetmonitor-ap-southeast-2", "internetmonitor-ap-southeast-3", "internetmonitor-ap-southeast-4", "internetmonitor-ca-central-1", "internetmonitor-eu-central-1", "internetmonitor-eu-central-2", "internetmonitor-eu-north-1", "internetmonitor-eu-south-1", "internetmonitor-eu-south-2", "internetmonitor-eu-west-1", "internetmonitor-eu-west-2", "internetmonitor-eu-west-3", "internetmonitor-me-central-1", "internetmonitor-me-south-1", "internetmonitor-sa-east-1", "internetmonitor-us-east-1", "internetmonitor-us-east-2", "internetmonitor-us-west-1", "internetmonitor-us-west-2" ]) } final class AmazonCloudWatchRUM: AWSNamedService, SubService { let name = "Amazon CloudWatch RUM" let ids = Set([ "rum-af-south-1", "rum-ap-east-1", "rum-ap-northeast-1", "rum-ap-northeast-2", "rum-ap-northeast-3", "rum-ap-south-1", "rum-ap-south-2", "rum-ap-southeast-1", "rum-ap-southeast-2", "rum-ap-southeast-3", "rum-ap-southeast-4", "rum-ap-southeast-5", "rum-ap-southeast-7", "rum-ca-central-1", "rum-ca-west-1", "rum-eu-central-1", "rum-eu-central-2", "rum-eu-north-1", "rum-eu-south-1", "rum-eu-south-2", "rum-eu-west-1", "rum-eu-west-2", "rum-eu-west-3", "rum-il-central-1", "rum-me-central-1", "rum-me-south-1", "rum-mx-central-1", "rum-sa-east-1", "rum-us-east-1", "rum-us-east-2", "rum-us-gov-east-1", "rum-us-gov-west-1", "rum-us-west-1", "rum-us-west-2" ]) } final class AmazonCloudWatchSynthetics: AWSNamedService, SubService { let name = "Amazon CloudWatch Synthetics" let ids = Set([ "cloudwatchsynthetics-af-south-1", "cloudwatchsynthetics-ap-east-1", "cloudwatchsynthetics-ap-east-2", "cloudwatchsynthetics-ap-northeast-1", "cloudwatchsynthetics-ap-northeast-2", "cloudwatchsynthetics-ap-northeast-3", "cloudwatchsynthetics-ap-south-1", "cloudwatchsynthetics-ap-south-2", "cloudwatchsynthetics-ap-southeast-1", "cloudwatchsynthetics-ap-southeast-2", "cloudwatchsynthetics-ap-southeast-3", "cloudwatchsynthetics-ap-southeast-4", "cloudwatchsynthetics-ap-southeast-5", "cloudwatchsynthetics-ap-southeast-6", "cloudwatchsynthetics-ap-southeast-7", "cloudwatchsynthetics-ca-central-1", "cloudwatchsynthetics-ca-west-1", "cloudwatchsynthetics-eu-central-1", "cloudwatchsynthetics-eu-central-2", "cloudwatchsynthetics-eu-north-1", "cloudwatchsynthetics-eu-south-1", "cloudwatchsynthetics-eu-south-2", "cloudwatchsynthetics-eu-west-1", "cloudwatchsynthetics-eu-west-2", "cloudwatchsynthetics-eu-west-3", "cloudwatchsynthetics-il-central-1", "cloudwatchsynthetics-me-central-1", "cloudwatchsynthetics-me-south-1", "cloudwatchsynthetics-mx-central-1", "cloudwatchsynthetics-sa-east-1", "cloudwatchsynthetics-us-east-1", "cloudwatchsynthetics-us-east-2", "cloudwatchsynthetics-us-gov-east-1", "cloudwatchsynthetics-us-gov-west-1", "cloudwatchsynthetics-us-west-1", "cloudwatchsynthetics-us-west-2" ]) } final class AmazonCodeCatalyst: AWSNamedService, SubService { let name = "Amazon CodeCatalyst" let ids = Set([ "codecatalyst-eu-west-1", "codecatalyst-us-west-2" ]) } final class AmazonCodeGuruProfiler: AWSNamedService, SubService { let name = "Amazon CodeGuru Profiler" let ids = Set([ "codeguru-profiler-ap-northeast-1", "codeguru-profiler-ap-southeast-1", "codeguru-profiler-ap-southeast-2", "codeguru-profiler-eu-central-1", "codeguru-profiler-eu-north-1", "codeguru-profiler-eu-west-1", "codeguru-profiler-eu-west-2", "codeguru-profiler-us-east-1", "codeguru-profiler-us-east-2", "codeguru-profiler-us-west-2" ]) } final class AmazonCodeGuruReviewer: AWSNamedService, SubService { let name = "Amazon CodeGuru Reviewer" let ids = Set([ "codeguru-reviewer-ap-northeast-1", "codeguru-reviewer-ap-southeast-1", "codeguru-reviewer-ap-southeast-2", "codeguru-reviewer-eu-central-1", "codeguru-reviewer-eu-north-1", "codeguru-reviewer-eu-west-1", "codeguru-reviewer-eu-west-2", "codeguru-reviewer-us-east-1", "codeguru-reviewer-us-east-2", "codeguru-reviewer-us-west-2" ]) } final class AmazonCognito: AWSNamedService, SubService { let name = "Amazon Cognito" let ids = Set([ "cognito-af-south-1", "cognito-ap-east-1", "cognito-ap-northeast-1", "cognito-ap-northeast-2", "cognito-ap-northeast-3", "cognito-ap-south-1", "cognito-ap-south-2", "cognito-ap-southeast-1", "cognito-ap-southeast-2", "cognito-ap-southeast-3", "cognito-ap-southeast-4", "cognito-ap-southeast-5", "cognito-ap-southeast-7", "cognito-ca-central-1", "cognito-ca-west-1", "cognito-eu-central-1", "cognito-eu-central-2", "cognito-eu-north-1", "cognito-eu-south-1", "cognito-eu-south-2", "cognito-eu-west-1", "cognito-eu-west-2", "cognito-eu-west-3", "cognito-il-central-1", "cognito-me-central-1", "cognito-me-south-1", "cognito-mx-central-1", "cognito-sa-east-1", "cognito-us-east-1", "cognito-us-east-2", "cognito-us-gov-east-1", "cognito-us-gov-west-1", "cognito-us-west-1", "cognito-us-west-2" ]) } final class AmazonComprehend: AWSNamedService, SubService { let name = "Amazon Comprehend" let ids = Set([ "comprehend-ap-northeast-1", "comprehend-ap-northeast-2", "comprehend-ap-south-1", "comprehend-ap-southeast-1", "comprehend-ap-southeast-2", "comprehend-ca-central-1", "comprehend-eu-central-1", "comprehend-eu-west-1", "comprehend-eu-west-2", "comprehend-us-east-1", "comprehend-us-east-2", "comprehend-us-gov-west-1", "comprehend-us-west-2" ]) } final class AmazonComprehendMedical: AWSNamedService, SubService { let name = "Amazon Comprehend Medical" let ids = Set([ "comprehendmedical-ap-southeast-2", "comprehendmedical-ca-central-1", "comprehendmedical-eu-west-1", "comprehendmedical-eu-west-2", "comprehendmedical-us-east-1", "comprehendmedical-us-east-2", "comprehendmedical-us-gov-west-1", "comprehendmedical-us-west-2" ]) } final class AmazonConnect: AWSNamedService, SubService { let name = "Amazon Connect" let ids = Set([ "connect-af-south-1", "connect-ap-northeast-1", "connect-ap-northeast-2", "connect-ap-southeast-1", "connect-ap-southeast-2", "connect-ca-central-1", "connect-eu-central-1", "connect-eu-west-2", "connect-us-east-1", "connect-us-gov-west-1", "connect-us-west-2" ]) } final class AmazonDataLifecycleManager: AWSNamedService, SubService { let name = "Amazon Data Lifecycle Manager" let ids = Set([ "dlm-af-south-1", "dlm-ap-east-1", "dlm-ap-east-2", "dlm-ap-northeast-1", "dlm-ap-northeast-2", "dlm-ap-northeast-3", "dlm-ap-south-1", "dlm-ap-south-2", "dlm-ap-southeast-1", "dlm-ap-southeast-2", "dlm-ap-southeast-3", "dlm-ap-southeast-4", "dlm-ap-southeast-5", "dlm-ap-southeast-6", "dlm-ap-southeast-7", "dlm-ca-central-1", "dlm-ca-west-1", "dlm-eu-central-1", "dlm-eu-central-2", "dlm-eu-north-1", "dlm-eu-south-1", "dlm-eu-south-2", "dlm-eu-west-1", "dlm-eu-west-2", "dlm-eu-west-3", "dlm-il-central-1", "dlm-me-central-1", "dlm-me-south-1", "dlm-mx-central-1", "dlm-sa-east-1", "dlm-us-east-1", "dlm-us-east-2", "dlm-us-gov-east-1", "dlm-us-gov-west-1", "dlm-us-west-1", "dlm-us-west-2" ]) } final class AmazonDataZone: AWSNamedService, SubService { let name = "Amazon DataZone" let ids = Set([ "datazone-af-south-1", "datazone-ap-east-1", "datazone-ap-northeast-1", "datazone-ap-northeast-2", "datazone-ap-south-1", "datazone-ap-southeast-1", "datazone-ap-southeast-2", "datazone-ap-southeast-5", "datazone-ap-southeast-7", "datazone-ca-central-1", "datazone-eu-central-1", "datazone-eu-central-2", "datazone-eu-north-1", "datazone-eu-south-2", "datazone-eu-west-1", "datazone-eu-west-2", "datazone-eu-west-3", "datazone-sa-east-1", "datazone-us-east-1", "datazone-us-east-2", "datazone-us-west-2" ]) } final class AmazonDetective: AWSNamedService, SubService { let name = "Amazon Detective" let ids = Set([ "detective-af-south-1", "detective-ap-east-1", "detective-ap-northeast-1", "detective-ap-northeast-2", "detective-ap-south-1", "detective-ap-southeast-1", "detective-ap-southeast-2", "detective-ca-central-1", "detective-eu-central-1", "detective-eu-north-1", "detective-eu-south-1", "detective-eu-west-1", "detective-eu-west-2", "detective-eu-west-3", "detective-il-central-1", "detective-me-south-1", "detective-sa-east-1", "detective-us-east-1", "detective-us-east-2", "detective-us-gov-east-1", "detective-us-gov-west-1", "detective-us-west-1", "detective-us-west-2" ]) } final class AmazonDevOpsGuru: AWSNamedService, SubService { let name = "Amazon DevOps Guru" let ids = Set([ "devops-guru-ap-northeast-1", "devops-guru-ap-northeast-2", "devops-guru-ap-south-1", "devops-guru-ap-southeast-1", "devops-guru-ap-southeast-2", "devops-guru-ca-central-1", "devops-guru-eu-central-1", "devops-guru-eu-north-1", "devops-guru-eu-west-1", "devops-guru-eu-west-2", "devops-guru-eu-west-3", "devops-guru-sa-east-1", "devops-guru-us-east-1", "devops-guru-us-east-2", "devops-guru-us-west-1", "devops-guru-us-west-2" ]) } final class AmazonDocumentDB: AWSNamedService, SubService { let name = "Amazon DocumentDB" let ids = Set([ "docdb-af-south-1", "docdb-ap-east-1", "docdb-ap-northeast-1", "docdb-ap-northeast-2", "docdb-ap-northeast-3", "docdb-ap-south-1", "docdb-ap-south-2", "docdb-ap-southeast-1", "docdb-ap-southeast-2", "docdb-ap-southeast-3", "docdb-ap-southeast-4", "docdb-ap-southeast-5", "docdb-ap-southeast-7", "docdb-ca-central-1", "docdb-eu-central-1", "docdb-eu-central-2", "docdb-eu-north-1", "docdb-eu-south-1", "docdb-eu-south-2", "docdb-eu-west-1", "docdb-eu-west-2", "docdb-eu-west-3", "docdb-il-central-1", "docdb-me-central-1", "docdb-mx-central-1", "docdb-sa-east-1", "docdb-us-east-1", "docdb-us-east-2", "docdb-us-gov-east-1", "docdb-us-gov-west-1", "docdb-us-west-2" ]) } final class AmazonDynamoDB: AWSNamedService, SubService { let name = "Amazon DynamoDB" let ids = Set([ "dynamodb-af-south-1", "dynamodb-ap-east-1", "dynamodb-ap-east-2", "dynamodb-ap-northeast-1", "dynamodb-ap-northeast-2", "dynamodb-ap-northeast-3", "dynamodb-ap-south-1", "dynamodb-ap-south-2", "dynamodb-ap-southeast-1", "dynamodb-ap-southeast-2", "dynamodb-ap-southeast-3", "dynamodb-ap-southeast-4", "dynamodb-ap-southeast-5", "dynamodb-ap-southeast-6", "dynamodb-ap-southeast-7", "dynamodb-ca-central-1", "dynamodb-ca-west-1", "dynamodb-eu-central-1", "dynamodb-eu-central-2", "dynamodb-eu-north-1", "dynamodb-eu-south-1", "dynamodb-eu-south-2", "dynamodb-eu-west-1", "dynamodb-eu-west-2", "dynamodb-eu-west-3", "dynamodb-il-central-1", "dynamodb-me-central-1", "dynamodb-me-south-1", "dynamodb-mx-central-1", "dynamodb-sa-east-1", "dynamodb-us-east-1", "dynamodb-us-east-2", "dynamodb-us-gov-east-1", "dynamodb-us-gov-west-1", "dynamodb-us-west-1", "dynamodb-us-west-2" ]) } final class AmazonEC2InstanceConnect: AWSNamedService, SubService { let name = "Amazon EC2 Instance Connect" let ids = Set([ "managedssh-af-south-1", "managedssh-ap-east-1", "managedssh-ap-northeast-1", "managedssh-ap-northeast-2", "managedssh-ap-northeast-3", "managedssh-ap-south-1", "managedssh-ap-south-2", "managedssh-ap-southeast-1", "managedssh-ap-southeast-2", "managedssh-ap-southeast-3", "managedssh-ap-southeast-4", "managedssh-ap-southeast-5", "managedssh-ap-southeast-7", "managedssh-ca-central-1", "managedssh-ca-west-1", "managedssh-eu-central-1", "managedssh-eu-central-2", "managedssh-eu-north-1", "managedssh-eu-south-1", "managedssh-eu-south-2", "managedssh-eu-west-1", "managedssh-eu-west-2", "managedssh-eu-west-3", "managedssh-il-central-1", "managedssh-me-central-1", "managedssh-me-south-1", "managedssh-mx-central-1", "managedssh-sa-east-1", "managedssh-us-east-1", "managedssh-us-east-2", "managedssh-us-gov-east-1", "managedssh-us-gov-west-1", "managedssh-us-west-1", "managedssh-us-west-2" ]) } final class AmazonEMRServerless: AWSNamedService, SubService { let name = "Amazon EMR Serverless" let ids = Set([ "emrserverless-af-south-1", "emrserverless-ap-east-1", "emrserverless-ap-northeast-1", "emrserverless-ap-northeast-2", "emrserverless-ap-northeast-3", "emrserverless-ap-south-1", "emrserverless-ap-southeast-1", "emrserverless-ap-southeast-2", "emrserverless-ap-southeast-3", "emrserverless-ap-southeast-4", "emrserverless-ap-southeast-5", "emrserverless-ca-central-1", "emrserverless-ca-west-1", "emrserverless-eu-central-1", "emrserverless-eu-central-2", "emrserverless-eu-north-1", "emrserverless-eu-south-1", "emrserverless-eu-south-2", "emrserverless-eu-west-1", "emrserverless-eu-west-2", "emrserverless-eu-west-3", "emrserverless-il-central-1", "emrserverless-me-central-1", "emrserverless-me-south-1", "emrserverless-sa-east-1", "emrserverless-us-east-1", "emrserverless-us-east-2", "emrserverless-us-gov-east-1", "emrserverless-us-gov-west-1", "emrserverless-us-west-1", "emrserverless-us-west-2" ]) } final class AmazonElastiCache: AWSNamedService, SubService { let name = "Amazon ElastiCache" let ids = Set([ "elasticache-af-south-1", "elasticache-ap-east-1", "elasticache-ap-east-2", "elasticache-ap-northeast-1", "elasticache-ap-northeast-2", "elasticache-ap-northeast-3", "elasticache-ap-south-1", "elasticache-ap-south-2", "elasticache-ap-southeast-1", "elasticache-ap-southeast-2", "elasticache-ap-southeast-3", "elasticache-ap-southeast-4", "elasticache-ap-southeast-5", "elasticache-ap-southeast-6", "elasticache-ap-southeast-7", "elasticache-ca-central-1", "elasticache-ca-west-1", "elasticache-eu-central-1", "elasticache-eu-central-2", "elasticache-eu-north-1", "elasticache-eu-south-1", "elasticache-eu-south-2", "elasticache-eu-west-1", "elasticache-eu-west-2", "elasticache-eu-west-3", "elasticache-il-central-1", "elasticache-me-central-1", "elasticache-me-south-1", "elasticache-mx-central-1", "elasticache-sa-east-1", "elasticache-us-east-1", "elasticache-us-east-2", "elasticache-us-gov-east-1", "elasticache-us-gov-west-1", "elasticache-us-west-1", "elasticache-us-west-2" ]) } final class AmazonElasticComputeCloud: AWSNamedService, SubService { let name = "Amazon Elastic Compute Cloud" let ids = Set([ "ec2-af-south-1", "ec2-ap-east-1", "ec2-ap-east-2", "ec2-ap-northeast-1", "ec2-ap-northeast-2", "ec2-ap-northeast-3", "ec2-ap-south-1", "ec2-ap-south-2", "ec2-ap-southeast-1", "ec2-ap-southeast-2", "ec2-ap-southeast-3", "ec2-ap-southeast-4", "ec2-ap-southeast-5", "ec2-ap-southeast-6", "ec2-ap-southeast-7", "ec2-ca-central-1", "ec2-ca-west-1", "ec2-eu-central-1", "ec2-eu-central-2", "ec2-eu-north-1", "ec2-eu-south-1", "ec2-eu-south-2", "ec2-eu-west-1", "ec2-eu-west-2", "ec2-eu-west-3", "ec2-il-central-1", "ec2-me-central-1", "ec2-me-south-1", "ec2-mx-central-1", "ec2-sa-east-1", "ec2-us-east-1", "ec2-us-east-2", "ec2-us-gov-east-1", "ec2-us-gov-west-1", "ec2-us-west-1", "ec2-us-west-2" ]) } final class AmazonElasticContainerRegistry: AWSNamedService, SubService { let name = "Amazon Elastic Container Registry" let ids = Set([ "ecr-af-south-1", "ecr-ap-east-1", "ecr-ap-east-2", "ecr-ap-northeast-1", "ecr-ap-northeast-2", "ecr-ap-northeast-3", "ecr-ap-south-1", "ecr-ap-south-2", "ecr-ap-southeast-1", "ecr-ap-southeast-2", "ecr-ap-southeast-3", "ecr-ap-southeast-4", "ecr-ap-southeast-5", "ecr-ap-southeast-6", "ecr-ap-southeast-7", "ecr-ca-central-1", "ecr-ca-west-1", "ecr-eu-central-1", "ecr-eu-central-2", "ecr-eu-north-1", "ecr-eu-south-1", "ecr-eu-south-2", "ecr-eu-west-1", "ecr-eu-west-2", "ecr-eu-west-3", "ecr-il-central-1", "ecr-me-central-1", "ecr-me-south-1", "ecr-mx-central-1", "ecr-sa-east-1", "ecr-us-east-1", "ecr-us-east-2", "ecr-us-gov-east-1", "ecr-us-gov-west-1", "ecr-us-west-1", "ecr-us-west-2" ]) } final class AmazonElasticContainerRegistryPublic: AWSNamedService, SubService { let name = "Amazon Elastic Container Registry Public" let ids = Set([ "spencer" ]) } final class AmazonElasticContainerService: AWSNamedService, SubService { let name = "Amazon Elastic Container Service" let ids = Set([ "ecs-af-south-1", "ecs-ap-east-1", "ecs-ap-east-2", "ecs-ap-northeast-1", "ecs-ap-northeast-2", "ecs-ap-northeast-3", "ecs-ap-south-1", "ecs-ap-south-2", "ecs-ap-southeast-1", "ecs-ap-southeast-2", "ecs-ap-southeast-3", "ecs-ap-southeast-4", "ecs-ap-southeast-5", "ecs-ap-southeast-6", "ecs-ap-southeast-7", "ecs-ca-central-1", "ecs-ca-west-1", "ecs-eu-central-1", "ecs-eu-central-2", "ecs-eu-north-1", "ecs-eu-south-1", "ecs-eu-south-2", "ecs-eu-west-1", "ecs-eu-west-2", "ecs-eu-west-3", "ecs-il-central-1", "ecs-me-central-1", "ecs-me-south-1", "ecs-mx-central-1", "ecs-sa-east-1", "ecs-us-east-1", "ecs-us-east-2", "ecs-us-gov-east-1", "ecs-us-gov-west-1", "ecs-us-west-1", "ecs-us-west-2" ]) } final class AmazonElasticFileSystem: AWSNamedService, SubService { let name = "Amazon Elastic File System" let ids = Set([ "elasticfilesystem-af-south-1", "elasticfilesystem-ap-east-1", "elasticfilesystem-ap-east-2", "elasticfilesystem-ap-northeast-1", "elasticfilesystem-ap-northeast-2", "elasticfilesystem-ap-northeast-3", "elasticfilesystem-ap-south-1", "elasticfilesystem-ap-south-2", "elasticfilesystem-ap-southeast-1", "elasticfilesystem-ap-southeast-2", "elasticfilesystem-ap-southeast-3", "elasticfilesystem-ap-southeast-4", "elasticfilesystem-ap-southeast-5", "elasticfilesystem-ap-southeast-6", "elasticfilesystem-ap-southeast-7", "elasticfilesystem-ca-central-1", "elasticfilesystem-ca-west-1", "elasticfilesystem-eu-central-1", "elasticfilesystem-eu-central-2", "elasticfilesystem-eu-north-1", "elasticfilesystem-eu-south-1", "elasticfilesystem-eu-south-2", "elasticfilesystem-eu-west-1", "elasticfilesystem-eu-west-2", "elasticfilesystem-eu-west-3", "elasticfilesystem-il-central-1", "elasticfilesystem-me-central-1", "elasticfilesystem-me-south-1", "elasticfilesystem-mx-central-1", "elasticfilesystem-sa-east-1", "elasticfilesystem-us-east-1", "elasticfilesystem-us-east-2", "elasticfilesystem-us-gov-east-1", "elasticfilesystem-us-gov-west-1", "elasticfilesystem-us-west-1", "elasticfilesystem-us-west-2" ]) } final class AmazonElasticKubernetesService: AWSNamedService, SubService { let name = "Amazon Elastic Kubernetes Service" let ids = Set([ "eks-af-south-1", "eks-ap-east-1", "eks-ap-east-2", "eks-ap-northeast-1", "eks-ap-northeast-2", "eks-ap-northeast-3", "eks-ap-south-1", "eks-ap-south-2", "eks-ap-southeast-1", "eks-ap-southeast-2", "eks-ap-southeast-3", "eks-ap-southeast-4", "eks-ap-southeast-5", "eks-ap-southeast-6", "eks-ap-southeast-7", "eks-ca-central-1", "eks-ca-west-1", "eks-eu-central-1", "eks-eu-central-2", "eks-eu-north-1", "eks-eu-south-1", "eks-eu-south-2", "eks-eu-west-1", "eks-eu-west-2", "eks-eu-west-3", "eks-il-central-1", "eks-me-central-1", "eks-me-south-1", "eks-mx-central-1", "eks-sa-east-1", "eks-us-east-1", "eks-us-east-2", "eks-us-gov-east-1", "eks-us-gov-west-1", "eks-us-west-1", "eks-us-west-2" ]) } final class AmazonElasticLoadBalancing: AWSNamedService, SubService { let name = "Amazon Elastic Load Balancing" let ids = Set([ "elb-af-south-1", "elb-ap-east-1", "elb-ap-east-2", "elb-ap-northeast-1", "elb-ap-northeast-2", "elb-ap-northeast-3", "elb-ap-south-1", "elb-ap-south-2", "elb-ap-southeast-1", "elb-ap-southeast-2", "elb-ap-southeast-3", "elb-ap-southeast-4", "elb-ap-southeast-5", "elb-ap-southeast-6", "elb-ap-southeast-7", "elb-ca-central-1", "elb-ca-west-1", "elb-eu-central-1", "elb-eu-central-2", "elb-eu-north-1", "elb-eu-south-1", "elb-eu-south-2", "elb-eu-west-1", "elb-eu-west-2", "elb-eu-west-3", "elb-il-central-1", "elb-me-central-1", "elb-me-south-1", "elb-mx-central-1", "elb-sa-east-1", "elb-us-east-1", "elb-us-east-2", "elb-us-gov-east-1", "elb-us-gov-west-1", "elb-us-west-1", "elb-us-west-2" ]) } final class AmazonElasticMapReduce: AWSNamedService, SubService { let name = "Amazon Elastic MapReduce" let ids = Set([ "emr-af-south-1", "emr-ap-east-1", "emr-ap-east-2", "emr-ap-northeast-1", "emr-ap-northeast-2", "emr-ap-northeast-3", "emr-ap-south-1", "emr-ap-south-2", "emr-ap-southeast-1", "emr-ap-southeast-2", "emr-ap-southeast-3", "emr-ap-southeast-4", "emr-ap-southeast-5", "emr-ap-southeast-6", "emr-ap-southeast-7", "emr-ca-central-1", "emr-ca-west-1", "emr-eu-central-1", "emr-eu-central-2", "emr-eu-north-1", "emr-eu-south-1", "emr-eu-south-2", "emr-eu-west-1", "emr-eu-west-2", "emr-eu-west-3", "emr-il-central-1", "emr-me-central-1", "emr-me-south-1", "emr-mx-central-1", "emr-sa-east-1", "emr-us-east-1", "emr-us-east-2", "emr-us-gov-east-1", "emr-us-gov-west-1", "emr-us-west-1", "emr-us-west-2" ]) } final class AmazonEventBridge: AWSNamedService, SubService { let name = "Amazon EventBridge" let ids = Set([ "events-af-south-1", "events-ap-east-1", "events-ap-east-2", "events-ap-northeast-1", "events-ap-northeast-2", "events-ap-northeast-3", "events-ap-south-1", "events-ap-south-2", "events-ap-southeast-1", "events-ap-southeast-2", "events-ap-southeast-3", "events-ap-southeast-4", "events-ap-southeast-5", "events-ap-southeast-6", "events-ap-southeast-7", "events-ca-central-1", "events-ca-west-1", "events-eu-central-1", "events-eu-central-2", "events-eu-north-1", "events-eu-south-1", "events-eu-south-2", "events-eu-west-1", "events-eu-west-2", "events-eu-west-3", "events-il-central-1", "events-me-central-1", "events-me-south-1", "events-mx-central-1", "events-sa-east-1", "events-us-east-1", "events-us-east-2", "events-us-gov-east-1", "events-us-gov-west-1", "events-us-west-1", "events-us-west-2" ]) } final class AmazonEventBridgeScheduler: AWSNamedService, SubService { let name = "Amazon EventBridge Scheduler" let ids = Set([ "scheduler-af-south-1", "scheduler-ap-east-1", "scheduler-ap-east-2", "scheduler-ap-northeast-1", "scheduler-ap-northeast-2", "scheduler-ap-northeast-3", "scheduler-ap-south-1", "scheduler-ap-south-2", "scheduler-ap-southeast-1", "scheduler-ap-southeast-2", "scheduler-ap-southeast-3", "scheduler-ap-southeast-4", "scheduler-ap-southeast-5", "scheduler-ap-southeast-6", "scheduler-ap-southeast-7", "scheduler-ca-central-1", "scheduler-ca-west-1", "scheduler-eu-central-1", "scheduler-eu-central-2", "scheduler-eu-north-1", "scheduler-eu-south-1", "scheduler-eu-south-2", "scheduler-eu-west-1", "scheduler-eu-west-2", "scheduler-eu-west-3", "scheduler-il-central-1", "scheduler-me-central-1", "scheduler-me-south-1", "scheduler-mx-central-1", "scheduler-sa-east-1", "scheduler-us-east-1", "scheduler-us-east-2", "scheduler-us-gov-east-1", "scheduler-us-gov-west-1", "scheduler-us-west-1", "scheduler-us-west-2" ]) } final class AmazonFSx: AWSNamedService, SubService { let name = "Amazon FSx" let ids = Set([ "fsx-af-south-1", "fsx-ap-east-1", "fsx-ap-east-2", "fsx-ap-northeast-1", "fsx-ap-northeast-2", "fsx-ap-northeast-3", "fsx-ap-south-1", "fsx-ap-south-2", "fsx-ap-southeast-1", "fsx-ap-southeast-2", "fsx-ap-southeast-3", "fsx-ap-southeast-4", "fsx-ap-southeast-5", "fsx-ap-southeast-7", "fsx-ca-central-1", "fsx-ca-west-1", "fsx-eu-central-1", "fsx-eu-central-2", "fsx-eu-north-1", "fsx-eu-south-1", "fsx-eu-south-2", "fsx-eu-west-1", "fsx-eu-west-2", "fsx-eu-west-3", "fsx-il-central-1", "fsx-me-central-1", "fsx-me-south-1", "fsx-mx-central-1", "fsx-sa-east-1", "fsx-us-east-1", "fsx-us-east-2", "fsx-us-gov-east-1", "fsx-us-gov-west-1", "fsx-us-west-1", "fsx-us-west-2" ]) } final class AmazonFinSpace: AWSNamedService, SubService { let name = "Amazon FinSpace" let ids = Set([ "finspace-ap-northeast-1", "finspace-ap-southeast-1", "finspace-ap-southeast-2", "finspace-ca-central-1", "finspace-eu-central-1", "finspace-eu-west-1", "finspace-eu-west-2", "finspace-us-east-1", "finspace-us-east-2", "finspace-us-west-2" ]) } final class AmazonForecast: AWSNamedService, SubService { let name = "Amazon Forecast" let ids = Set([ "amazonforecast-ap-northeast-1", "amazonforecast-ap-northeast-2", "amazonforecast-ap-south-1", "amazonforecast-ap-southeast-1", "amazonforecast-ap-southeast-2", "amazonforecast-eu-central-1", "amazonforecast-eu-west-1", "amazonforecast-us-east-1", "amazonforecast-us-east-2", "amazonforecast-us-west-2" ]) } final class AmazonFraudDetector: AWSNamedService, SubService { let name = "Amazon Fraud Detector" let ids = Set([ "frauddetector-ap-southeast-1", "frauddetector-ap-southeast-2", "frauddetector-eu-west-1", "frauddetector-us-east-1", "frauddetector-us-east-2", "frauddetector-us-west-2" ]) } final class AmazonFreeRTOS: AWSNamedService, SubService { let name = "Amazon FreeRTOS" let ids = Set([ "freertos-ap-east-1", "freertos-ap-northeast-1", "freertos-ap-northeast-2", "freertos-ap-south-1", "freertos-ap-southeast-1", "freertos-ap-southeast-2", "freertos-ca-central-1", "freertos-eu-central-1", "freertos-eu-north-1", "freertos-eu-west-1", "freertos-eu-west-2", "freertos-eu-west-3", "freertos-me-south-1", "freertos-sa-east-1", "freertos-us-east-1", "freertos-us-east-2", "freertos-us-west-1", "freertos-us-west-2" ]) } final class AmazonGameLiftServers: AWSNamedService, SubService { let name = "Amazon GameLift Servers" let ids = Set([ "gamelift-af-south-1", "gamelift-ap-east-1", "gamelift-ap-northeast-1", "gamelift-ap-northeast-2", "gamelift-ap-northeast-3", "gamelift-ap-south-1", "gamelift-ap-southeast-1", "gamelift-ap-southeast-2", "gamelift-ap-southeast-5", "gamelift-ap-southeast-7", "gamelift-ca-central-1", "gamelift-eu-central-1", "gamelift-eu-north-1", "gamelift-eu-south-1", "gamelift-eu-west-1", "gamelift-eu-west-2", "gamelift-eu-west-3", "gamelift-me-south-1", "gamelift-sa-east-1", "gamelift-us-east-1", "gamelift-us-east-2", "gamelift-us-west-1", "gamelift-us-west-2" ]) } final class AmazonGameLiftStreams: AWSNamedService, SubService { let name = "Amazon GameLift Streams" let ids = Set([ "gameliftstreams-ap-northeast-1", "gameliftstreams-eu-central-1", "gameliftstreams-us-east-2", "gameliftstreams-us-west-2" ]) } final class AmazonGlacier: AWSNamedService, SubService { let name = "Amazon Glacier" let ids = Set([ "glacier-af-south-1", "glacier-ap-east-1", "glacier-ap-east-2", "glacier-ap-northeast-1", "glacier-ap-northeast-2", "glacier-ap-northeast-3", "glacier-ap-south-1", "glacier-ap-south-2", "glacier-ap-southeast-1", "glacier-ap-southeast-2", "glacier-ap-southeast-3", "glacier-ap-southeast-4", "glacier-ap-southeast-6", "glacier-ca-central-1", "glacier-ca-west-1", "glacier-eu-central-1", "glacier-eu-central-2", "glacier-eu-north-1", "glacier-eu-south-1", "glacier-eu-south-2", "glacier-eu-west-1", "glacier-eu-west-2", "glacier-eu-west-3", "glacier-il-central-1", "glacier-me-central-1", "glacier-me-south-1", "glacier-sa-east-1", "glacier-us-east-1", "glacier-us-east-2", "glacier-us-gov-east-1", "glacier-us-gov-west-1", "glacier-us-west-1", "glacier-us-west-2" ]) } final class AmazonGuardDuty: AWSNamedService, SubService { let name = "Amazon GuardDuty" let ids = Set([ "guardduty-af-south-1", "guardduty-ap-east-1", "guardduty-ap-east-2", "guardduty-ap-northeast-1", "guardduty-ap-northeast-2", "guardduty-ap-northeast-3", "guardduty-ap-south-1", "guardduty-ap-south-2", "guardduty-ap-southeast-1", "guardduty-ap-southeast-2", "guardduty-ap-southeast-3", "guardduty-ap-southeast-4", "guardduty-ap-southeast-5", "guardduty-ap-southeast-6", "guardduty-ap-southeast-7", "guardduty-ca-central-1", "guardduty-ca-west-1", "guardduty-eu-central-1", "guardduty-eu-central-2", "guardduty-eu-north-1", "guardduty-eu-south-1", "guardduty-eu-south-2", "guardduty-eu-west-1", "guardduty-eu-west-2", "guardduty-eu-west-3", "guardduty-il-central-1", "guardduty-me-central-1", "guardduty-me-south-1", "guardduty-mx-central-1", "guardduty-sa-east-1", "guardduty-us-east-1", "guardduty-us-east-2", "guardduty-us-gov-east-1", "guardduty-us-gov-west-1", "guardduty-us-west-1", "guardduty-us-west-2" ]) } final class AmazonInspector: AWSNamedService, SubService { let name = "Amazon Inspector" let ids = Set([ "inspector-af-south-1", "inspector-ap-east-1", "inspector-ap-northeast-1", "inspector-ap-northeast-2", "inspector-ap-northeast-3", "inspector-ap-south-1", "inspector-ap-south-2", "inspector-ap-southeast-1", "inspector-ap-southeast-2", "inspector-ap-southeast-3", "inspector-ap-southeast-4", "inspector-ap-southeast-5", "inspector-ap-southeast-7", "inspector-ca-central-1", "inspector-ca-west-1", "inspector-eu-central-1", "inspector-eu-central-2", "inspector-eu-north-1", "inspector-eu-south-1", "inspector-eu-south-2", "inspector-eu-west-1", "inspector-eu-west-2", "inspector-eu-west-3", "inspector-il-central-1", "inspector-me-central-1", "inspector-me-south-1", "inspector-mx-central-1", "inspector-sa-east-1", "inspector-us-east-1", "inspector-us-east-2", "inspector-us-gov-east-1", "inspector-us-gov-west-1", "inspector-us-west-1", "inspector-us-west-2" ]) } final class AmazonInteractiveVideoService: AWSNamedService, SubService { let name = "Amazon Interactive Video Service" let ids = Set([ "ivs-ap-northeast-1", "ivs-ap-northeast-2", "ivs-ap-south-1", "ivs-eu-central-1", "ivs-eu-west-1", "ivs-us-east-1", "ivs-us-west-2" ]) } final class AmazonKendra: AWSNamedService, SubService { let name = "Amazon Kendra" let ids = Set([ "kendra-ap-northeast-1", "kendra-ap-south-1", "kendra-ap-southeast-1", "kendra-ap-southeast-2", "kendra-ca-central-1", "kendra-eu-west-1", "kendra-eu-west-2", "kendra-us-east-1", "kendra-us-east-2", "kendra-us-gov-west-1", "kendra-us-west-2" ]) } final class AmazonKendraIntelligentRanking: AWSNamedService, SubService { let name = "Amazon Kendra Intelligent Ranking" let ids = Set([ "kendraranking-ap-northeast-1", "kendraranking-ap-south-1", "kendraranking-ap-southeast-1", "kendraranking-ap-southeast-2", "kendraranking-ca-central-1", "kendraranking-eu-west-1", "kendraranking-us-east-1", "kendraranking-us-east-2", "kendraranking-us-west-2" ]) } final class AmazonKeyspaces: AWSNamedService, SubService { let name = "Amazon Keyspaces" let ids = Set([ "cassandra-ap-east-1", "cassandra-ap-northeast-1", "cassandra-ap-northeast-2", "cassandra-ap-south-1", "cassandra-ap-southeast-1", "cassandra-ap-southeast-2", "cassandra-ca-central-1", "cassandra-eu-central-1", "cassandra-eu-north-1", "cassandra-eu-west-1", "cassandra-eu-west-2", "cassandra-eu-west-3", "cassandra-me-south-1", "cassandra-sa-east-1", "cassandra-us-east-1", "cassandra-us-east-2", "cassandra-us-west-1", "cassandra-us-west-2" ]) } final class AmazonKinesisDataStreams: AWSNamedService, SubService { let name = "Amazon Kinesis Data Streams" let ids = Set([ "kinesis-af-south-1", "kinesis-ap-east-1", "kinesis-ap-east-2", "kinesis-ap-northeast-1", "kinesis-ap-northeast-2", "kinesis-ap-northeast-3", "kinesis-ap-south-1", "kinesis-ap-south-2", "kinesis-ap-southeast-1", "kinesis-ap-southeast-2", "kinesis-ap-southeast-3", "kinesis-ap-southeast-4", "kinesis-ap-southeast-5", "kinesis-ap-southeast-6", "kinesis-ap-southeast-7", "kinesis-ca-central-1", "kinesis-ca-west-1", "kinesis-eu-central-1", "kinesis-eu-central-2", "kinesis-eu-north-1", "kinesis-eu-south-1", "kinesis-eu-south-2", "kinesis-eu-west-1", "kinesis-eu-west-2", "kinesis-eu-west-3", "kinesis-il-central-1", "kinesis-me-central-1", "kinesis-me-south-1", "kinesis-mx-central-1", "kinesis-sa-east-1", "kinesis-us-east-1", "kinesis-us-east-2", "kinesis-us-gov-east-1", "kinesis-us-gov-west-1", "kinesis-us-west-1", "kinesis-us-west-2" ]) } final class AmazonKinesisFirehose: AWSNamedService, SubService { let name = "Amazon Kinesis Firehose" let ids = Set([ "firehose-af-south-1", "firehose-ap-east-1", "firehose-ap-east-2", "firehose-ap-northeast-1", "firehose-ap-northeast-2", "firehose-ap-northeast-3", "firehose-ap-south-1", "firehose-ap-south-2", "firehose-ap-southeast-1", "firehose-ap-southeast-2", "firehose-ap-southeast-3", "firehose-ap-southeast-4", "firehose-ap-southeast-5", "firehose-ap-southeast-6", "firehose-ap-southeast-7", "firehose-ca-central-1", "firehose-ca-west-1", "firehose-eu-central-1", "firehose-eu-central-2", "firehose-eu-north-1", "firehose-eu-south-1", "firehose-eu-south-2", "firehose-eu-west-1", "firehose-eu-west-2", "firehose-eu-west-3", "firehose-il-central-1", "firehose-me-central-1", "firehose-me-south-1", "firehose-mx-central-1", "firehose-sa-east-1", "firehose-us-east-1", "firehose-us-east-2", "firehose-us-gov-east-1", "firehose-us-gov-west-1", "firehose-us-west-1", "firehose-us-west-2" ]) } final class AmazonKinesisVideoStreams: AWSNamedService, SubService { let name = "Amazon Kinesis Video Streams" let ids = Set([ "kinesisvideo-af-south-1", "kinesisvideo-ap-east-1", "kinesisvideo-ap-northeast-1", "kinesisvideo-ap-northeast-2", "kinesisvideo-ap-south-1", "kinesisvideo-ap-southeast-1", "kinesisvideo-ap-southeast-2", "kinesisvideo-ap-southeast-5", "kinesisvideo-ca-central-1", "kinesisvideo-eu-central-1", "kinesisvideo-eu-south-2", "kinesisvideo-eu-west-1", "kinesisvideo-eu-west-2", "kinesisvideo-eu-west-3", "kinesisvideo-me-south-1", "kinesisvideo-sa-east-1", "kinesisvideo-us-east-1", "kinesisvideo-us-east-2", "kinesisvideo-us-gov-east-1", "kinesisvideo-us-gov-west-1", "kinesisvideo-us-west-2" ]) } final class AmazonLex: AWSNamedService, SubService { let name = "Amazon Lex" let ids = Set([ "lex-af-south-1", "lex-ap-northeast-1", "lex-ap-northeast-2", "lex-ap-southeast-1", "lex-ap-southeast-2", "lex-ca-central-1", "lex-eu-central-1", "lex-eu-west-1", "lex-eu-west-2", "lex-us-east-1", "lex-us-gov-west-1", "lex-us-west-2" ]) } final class AmazonLightsail: AWSNamedService, SubService { let name = "Amazon Lightsail" let ids = Set([ "lightsail-ap-northeast-1", "lightsail-ap-northeast-2", "lightsail-ap-south-1", "lightsail-ap-southeast-1", "lightsail-ap-southeast-2", "lightsail-ap-southeast-3", "lightsail-ca-central-1", "lightsail-eu-central-1", "lightsail-eu-north-1", "lightsail-eu-west-1", "lightsail-eu-west-2", "lightsail-eu-west-3", "lightsail-us-east-1", "lightsail-us-east-2", "lightsail-us-west-2" ]) } final class AmazonLocationService: AWSNamedService, SubService { let name = "Amazon Location Service" let ids = Set([ "locationservice-ap-northeast-1", "locationservice-ap-south-1", "locationservice-ap-southeast-1", "locationservice-ap-southeast-2", "locationservice-ap-southeast-5", "locationservice-ca-central-1", "locationservice-eu-central-1", "locationservice-eu-north-1", "locationservice-eu-south-2", "locationservice-eu-west-1", "locationservice-eu-west-2", "locationservice-sa-east-1", "locationservice-us-east-1", "locationservice-us-east-2", "locationservice-us-gov-west-1", "locationservice-us-west-2" ]) } final class AmazonLookoutForEquipment: AWSNamedService, SubService { let name = "Amazon Lookout for Equipment" let ids = Set([ "lookoutequipment-ap-northeast-2", "lookoutequipment-eu-west-1", "lookoutequipment-us-east-1" ]) } final class AmazonMQ: AWSNamedService, SubService { let name = "Amazon MQ" let ids = Set([ "mq-af-south-1", "mq-ap-east-1", "mq-ap-east-2", "mq-ap-northeast-1", "mq-ap-northeast-2", "mq-ap-northeast-3", "mq-ap-south-1", "mq-ap-south-2", "mq-ap-southeast-1", "mq-ap-southeast-2", "mq-ap-southeast-3", "mq-ap-southeast-4", "mq-ap-southeast-5", "mq-ap-southeast-6", "mq-ap-southeast-7", "mq-ca-central-1", "mq-ca-west-1", "mq-eu-central-1", "mq-eu-central-2", "mq-eu-north-1", "mq-eu-south-1", "mq-eu-south-2", "mq-eu-west-1", "mq-eu-west-2", "mq-eu-west-3", "mq-il-central-1", "mq-me-central-1", "mq-me-south-1", "mq-mx-central-1", "mq-sa-east-1", "mq-us-east-1", "mq-us-east-2", "mq-us-gov-east-1", "mq-us-gov-west-1", "mq-us-west-1", "mq-us-west-2" ]) } final class AmazonMachineLearning: AWSNamedService, SubService { let name = "Amazon Machine Learning" let ids = Set([ "aml-eu-west-1", "aml-us-east-1" ]) } final class AmazonMacie: AWSNamedService, SubService { let name = "Amazon Macie" let ids = Set([ "macie-af-south-1", "macie-ap-east-1", "macie-ap-northeast-1", "macie-ap-northeast-2", "macie-ap-northeast-3", "macie-ap-south-1", "macie-ap-southeast-1", "macie-ap-southeast-2", "macie-ca-central-1", "macie-eu-central-1", "macie-eu-north-1", "macie-eu-south-1", "macie-eu-west-1", "macie-eu-west-2", "macie-eu-west-3", "macie-il-central-1", "macie-me-south-1", "macie-sa-east-1", "macie-us-east-1", "macie-us-east-2", "macie-us-west-1", "macie-us-west-2" ]) } final class AmazonManagedBlockchain: AWSNamedService, SubService { let name = "Amazon Managed Blockchain" let ids = Set([ "managedblockchain-ap-northeast-1", "managedblockchain-ap-northeast-2", "managedblockchain-ap-southeast-1", "managedblockchain-eu-west-1", "managedblockchain-eu-west-2", "managedblockchain-us-east-1", "managedblockchain-us-gov-west-1" ]) } final class AmazonManagedGrafana: AWSNamedService, SubService { let name = "Amazon Managed Grafana" let ids = Set([ "grafana-ap-northeast-1", "grafana-ap-northeast-2", "grafana-ap-southeast-1", "grafana-ap-southeast-2", "grafana-eu-central-1", "grafana-eu-west-1", "grafana-eu-west-2", "grafana-us-east-1", "grafana-us-east-2", "grafana-us-gov-east-1", "grafana-us-gov-west-1", "grafana-us-west-2" ]) } final class AmazonManagedServiceForApacheFlink: AWSNamedService, SubService { let name = "Amazon Managed Service for Apache Flink" let ids = Set([ "kinesisanalytics-af-south-1", "kinesisanalytics-ap-east-1", "kinesisanalytics-ap-east-2", "kinesisanalytics-ap-northeast-1", "kinesisanalytics-ap-northeast-2", "kinesisanalytics-ap-northeast-3", "kinesisanalytics-ap-south-1", "kinesisanalytics-ap-south-2", "kinesisanalytics-ap-southeast-1", "kinesisanalytics-ap-southeast-2", "kinesisanalytics-ap-southeast-3", "kinesisanalytics-ap-southeast-4", "kinesisanalytics-ap-southeast-5", "kinesisanalytics-ap-southeast-6", "kinesisanalytics-ap-southeast-7", "kinesisanalytics-ca-central-1", "kinesisanalytics-ca-west-1", "kinesisanalytics-eu-central-1", "kinesisanalytics-eu-central-2", "kinesisanalytics-eu-north-1", "kinesisanalytics-eu-south-1", "kinesisanalytics-eu-south-2", "kinesisanalytics-eu-west-1", "kinesisanalytics-eu-west-2", "kinesisanalytics-eu-west-3", "kinesisanalytics-il-central-1", "kinesisanalytics-me-central-1", "kinesisanalytics-me-south-1", "kinesisanalytics-mx-central-1", "kinesisanalytics-sa-east-1", "kinesisanalytics-us-east-1", "kinesisanalytics-us-east-2", "kinesisanalytics-us-gov-east-1", "kinesisanalytics-us-gov-west-1", "kinesisanalytics-us-west-1", "kinesisanalytics-us-west-2" ]) } final class AmazonManagedServiceForPrometheus: AWSNamedService, SubService { let name = "Amazon Managed Service for Prometheus" let ids = Set([ "aps-ap-northeast-1", "aps-ap-southeast-1", "aps-ap-southeast-2", "aps-eu-central-1", "aps-eu-north-1", "aps-eu-west-1", "aps-us-east-1", "aps-us-east-2", "aps-us-gov-east-1", "aps-us-gov-west-1", "aps-us-west-2" ]) } final class AmazonManagedStreamingForApacheKafka: AWSNamedService, SubService { let name = "Amazon Managed Streaming for Apache Kafka" let ids = Set([ "kafka-af-south-1", "kafka-ap-east-1", "kafka-ap-east-2", "kafka-ap-northeast-1", "kafka-ap-northeast-2", "kafka-ap-northeast-3", "kafka-ap-south-1", "kafka-ap-south-2", "kafka-ap-southeast-1", "kafka-ap-southeast-2", "kafka-ap-southeast-3", "kafka-ap-southeast-4", "kafka-ap-southeast-5", "kafka-ap-southeast-6", "kafka-ap-southeast-7", "kafka-ca-central-1", "kafka-ca-west-1", "kafka-eu-central-1", "kafka-eu-central-2", "kafka-eu-north-1", "kafka-eu-south-1", "kafka-eu-south-2", "kafka-eu-west-1", "kafka-eu-west-2", "kafka-eu-west-3", "kafka-il-central-1", "kafka-me-central-1", "kafka-me-south-1", "kafka-mx-central-1", "kafka-sa-east-1", "kafka-us-east-1", "kafka-us-east-2", "kafka-us-gov-east-1", "kafka-us-gov-west-1", "kafka-us-west-1", "kafka-us-west-2" ]) } final class AmazonManagedWorkflowsForApacheAirflow: AWSNamedService, SubService { let name = "Amazon Managed Workflows for Apache Airflow" let ids = Set([ "airflow-af-south-1", "airflow-ap-east-1", "airflow-ap-northeast-1", "airflow-ap-northeast-2", "airflow-ap-northeast-3", "airflow-ap-south-1", "airflow-ap-south-2", "airflow-ap-southeast-1", "airflow-ap-southeast-2", "airflow-ap-southeast-3", "airflow-ap-southeast-4", "airflow-ap-southeast-5", "airflow-ap-southeast-7", "airflow-ca-central-1", "airflow-ca-west-1", "airflow-eu-central-1", "airflow-eu-central-2", "airflow-eu-north-1", "airflow-eu-south-1", "airflow-eu-south-2", "airflow-eu-west-1", "airflow-eu-west-2", "airflow-eu-west-3", "airflow-il-central-1", "airflow-me-central-1", "airflow-me-south-1", "airflow-sa-east-1", "airflow-us-east-1", "airflow-us-east-2", "airflow-us-west-1", "airflow-us-west-2" ]) } final class AmazonMemoryDBForRedis: AWSNamedService, SubService { let name = "Amazon MemoryDB for Redis" let ids = Set([ "memorydb-ap-east-1", "memorydb-ap-northeast-1", "memorydb-ap-northeast-2", "memorydb-ap-south-1", "memorydb-ap-southeast-1", "memorydb-ap-southeast-2", "memorydb-ca-central-1", "memorydb-eu-central-1", "memorydb-eu-north-1", "memorydb-eu-south-1", "memorydb-eu-south-2", "memorydb-eu-west-1", "memorydb-eu-west-2", "memorydb-eu-west-3", "memorydb-sa-east-1", "memorydb-us-east-1", "memorydb-us-east-2", "memorydb-us-gov-east-1", "memorydb-us-gov-west-1", "memorydb-us-west-1", "memorydb-us-west-2" ]) } final class AmazonMonitron: AWSNamedService, SubService { let name = "Amazon Monitron" let ids = Set([ "monitron-ap-southeast-2", "monitron-eu-west-1", "monitron-us-east-1" ]) } final class AmazonNeptune: AWSNamedService, SubService { let name = "Amazon Neptune" let ids = Set([ "neptune-db-af-south-1", "neptune-db-ap-east-1", "neptune-db-ap-northeast-1", "neptune-db-ap-northeast-2", "neptune-db-ap-northeast-3", "neptune-db-ap-south-1", "neptune-db-ap-southeast-1", "neptune-db-ap-southeast-2", "neptune-db-ap-southeast-3", "neptune-db-ap-southeast-4", "neptune-db-ap-southeast-5", "neptune-db-ca-central-1", "neptune-db-ca-west-1", "neptune-db-eu-central-1", "neptune-db-eu-central-2", "neptune-db-eu-north-1", "neptune-db-eu-south-2", "neptune-db-eu-west-1", "neptune-db-eu-west-2", "neptune-db-eu-west-3", "neptune-db-il-central-1", "neptune-db-me-central-1", "neptune-db-me-south-1", "neptune-db-sa-east-1", "neptune-db-us-east-1", "neptune-db-us-east-2", "neptune-db-us-gov-east-1", "neptune-db-us-gov-west-1", "neptune-db-us-west-1", "neptune-db-us-west-2" ]) } final class AmazonOneEnterprise: AWSNamedService, SubService { let name = "Amazon One Enterprise" let ids = Set([ "one-us-east-1" ]) } final class AmazonOpenSearchService: AWSNamedService, SubService { let name = "Amazon OpenSearch Service" let ids = Set([ "elasticsearch-af-south-1", "elasticsearch-ap-east-1", "elasticsearch-ap-east-2", "elasticsearch-ap-northeast-1", "elasticsearch-ap-northeast-2", "elasticsearch-ap-northeast-3", "elasticsearch-ap-south-1", "elasticsearch-ap-south-2", "elasticsearch-ap-southeast-1", "elasticsearch-ap-southeast-2", "elasticsearch-ap-southeast-3", "elasticsearch-ap-southeast-4", "elasticsearch-ap-southeast-5", "elasticsearch-ap-southeast-6", "elasticsearch-ap-southeast-7", "elasticsearch-ca-central-1", "elasticsearch-ca-west-1", "elasticsearch-eu-central-1", "elasticsearch-eu-central-2", "elasticsearch-eu-north-1", "elasticsearch-eu-south-1", "elasticsearch-eu-south-2", "elasticsearch-eu-west-1", "elasticsearch-eu-west-2", "elasticsearch-eu-west-3", "elasticsearch-il-central-1", "elasticsearch-me-central-1", "elasticsearch-me-south-1", "elasticsearch-mx-central-1", "elasticsearch-sa-east-1", "elasticsearch-us-east-1", "elasticsearch-us-east-2", "elasticsearch-us-gov-east-1", "elasticsearch-us-gov-west-1", "elasticsearch-us-west-1", "elasticsearch-us-west-2" ]) } final class AmazonPersonalize: AWSNamedService, SubService { let name = "Amazon Personalize" let ids = Set([ "personalize-ap-northeast-1", "personalize-ap-northeast-2", "personalize-ap-south-1", "personalize-ap-southeast-1", "personalize-ap-southeast-2", "personalize-ca-central-1", "personalize-eu-central-1", "personalize-eu-west-1", "personalize-us-east-1", "personalize-us-east-2", "personalize-us-west-2" ]) } final class AmazonPinpoint: AWSNamedService, SubService { let name = "Amazon Pinpoint" let ids = Set([ "pinpoint-ap-northeast-1", "pinpoint-ap-northeast-2", "pinpoint-ap-south-1", "pinpoint-ap-southeast-1", "pinpoint-ap-southeast-2", "pinpoint-ca-central-1", "pinpoint-eu-central-1", "pinpoint-eu-west-1", "pinpoint-eu-west-2", "pinpoint-us-east-1", "pinpoint-us-east-2", "pinpoint-us-gov-west-1", "pinpoint-us-west-2" ]) } final class AmazonPolly: AWSNamedService, SubService { let name = "Amazon Polly" let ids = Set([ "polly-af-south-1", "polly-ap-east-1", "polly-ap-northeast-1", "polly-ap-northeast-2", "polly-ap-northeast-3", "polly-ap-south-1", "polly-ap-southeast-1", "polly-ap-southeast-2", "polly-ap-southeast-5", "polly-ca-central-1", "polly-eu-central-1", "polly-eu-central-2", "polly-eu-north-1", "polly-eu-south-2", "polly-eu-west-1", "polly-eu-west-2", "polly-eu-west-3", "polly-me-south-1", "polly-sa-east-1", "polly-us-east-1", "polly-us-east-2", "polly-us-gov-west-1", "polly-us-west-1", "polly-us-west-2" ]) } final class AmazonQApps: AWSNamedService, SubService { let name = "Amazon Q Apps" let ids = Set([ "qapps-us-east-1", "qapps-us-west-2" ]) } final class AmazonQBusiness: AWSNamedService, SubService { let name = "Amazon Q Business" let ids = Set([ "qbusiness-ap-southeast-2", "qbusiness-eu-west-1", "qbusiness-us-east-1", "qbusiness-us-west-2" ]) } final class AmazonQuickSuite: AWSNamedService, SubService { let name = "Amazon Quick Suite" let ids = Set([ "quicksight-af-south-1", "quicksight-ap-northeast-1", "quicksight-ap-northeast-2", "quicksight-ap-south-1", "quicksight-ap-southeast-1", "quicksight-ap-southeast-2", "quicksight-ap-southeast-3", "quicksight-ap-southeast-5", "quicksight-ca-central-1", "quicksight-eu-central-1", "quicksight-eu-central-2", "quicksight-eu-north-1", "quicksight-eu-south-1", "quicksight-eu-south-2", "quicksight-eu-west-1", "quicksight-eu-west-2", "quicksight-eu-west-3", "quicksight-il-central-1", "quicksight-me-central-1", "quicksight-sa-east-1", "quicksight-us-east-1", "quicksight-us-east-2", "quicksight-us-gov-east-1", "quicksight-us-gov-west-1", "quicksight-us-west-2" ]) } final class AmazonRedshift: AWSNamedService, SubService { let name = "Amazon Redshift" let ids = Set([ "redshift-af-south-1", "redshift-ap-east-1", "redshift-ap-east-2", "redshift-ap-northeast-1", "redshift-ap-northeast-2", "redshift-ap-northeast-3", "redshift-ap-south-1", "redshift-ap-south-2", "redshift-ap-southeast-1", "redshift-ap-southeast-2", "redshift-ap-southeast-3", "redshift-ap-southeast-4", "redshift-ap-southeast-5", "redshift-ap-southeast-6", "redshift-ap-southeast-7", "redshift-ca-central-1", "redshift-ca-west-1", "redshift-eu-central-1", "redshift-eu-central-2", "redshift-eu-north-1", "redshift-eu-south-1", "redshift-eu-south-2", "redshift-eu-west-1", "redshift-eu-west-2", "redshift-eu-west-3", "redshift-il-central-1", "redshift-me-central-1", "redshift-me-south-1", "redshift-mx-central-1", "redshift-sa-east-1", "redshift-us-east-1", "redshift-us-east-2", "redshift-us-gov-east-1", "redshift-us-gov-west-1", "redshift-us-west-1", "redshift-us-west-2" ]) } final class AmazonRekognition: AWSNamedService, SubService { let name = "Amazon Rekognition" let ids = Set([ "rekognition-ap-northeast-1", "rekognition-ap-northeast-2", "rekognition-ap-south-1", "rekognition-ap-southeast-1", "rekognition-ap-southeast-2", "rekognition-ca-central-1", "rekognition-eu-central-1", "rekognition-eu-south-2", "rekognition-eu-west-1", "rekognition-eu-west-2", "rekognition-il-central-1", "rekognition-us-east-1", "rekognition-us-east-2", "rekognition-us-gov-west-1", "rekognition-us-west-1", "rekognition-us-west-2" ]) } final class AmazonRelationalDatabaseService: AWSNamedService, SubService { let name = "Amazon Relational Database Service" let ids = Set([ "rds-af-south-1", "rds-ap-east-1", "rds-ap-east-2", "rds-ap-northeast-1", "rds-ap-northeast-2", "rds-ap-northeast-3", "rds-ap-south-1", "rds-ap-south-2", "rds-ap-southeast-1", "rds-ap-southeast-2", "rds-ap-southeast-3", "rds-ap-southeast-4", "rds-ap-southeast-5", "rds-ap-southeast-6", "rds-ap-southeast-7", "rds-ca-central-1", "rds-ca-west-1", "rds-eu-central-1", "rds-eu-central-2", "rds-eu-north-1", "rds-eu-south-1", "rds-eu-south-2", "rds-eu-west-1", "rds-eu-west-2", "rds-eu-west-3", "rds-il-central-1", "rds-me-central-1", "rds-me-south-1", "rds-mx-central-1", "rds-sa-east-1", "rds-us-east-1", "rds-us-east-2", "rds-us-gov-east-1", "rds-us-gov-west-1", "rds-us-west-1", "rds-us-west-2" ]) } final class AmazonRoute53: AWSNamedService, SubService { let name = "Amazon Route 53" let ids = Set([ "route53", "route53-us-gov-east-1", "route53-us-gov-west-1" ]) } final class AmazonRoute53ApplicationRecoveryController: AWSNamedService, SubService { let name = "Amazon Route 53 Application Recovery Controller" let ids = Set([ "route53apprecoverycontroller" ]) } final class AmazonRoute53DomainRegistration: AWSNamedService, SubService { let name = "Amazon Route 53 Domain Registration" let ids = Set([ "route53domainregistration" ]) } final class AmazonRoute53PrivateDNS: AWSNamedService, SubService { let name = "Amazon Route 53 Private DNS" let ids = Set([ "route53privatedns-af-south-1", "route53privatedns-ap-east-1", "route53privatedns-ap-east-2", "route53privatedns-ap-northeast-1", "route53privatedns-ap-northeast-2", "route53privatedns-ap-northeast-3", "route53privatedns-ap-south-1", "route53privatedns-ap-south-2", "route53privatedns-ap-southeast-1", "route53privatedns-ap-southeast-2", "route53privatedns-ap-southeast-3", "route53privatedns-ap-southeast-4", "route53privatedns-ap-southeast-5", "route53privatedns-ap-southeast-6", "route53privatedns-ap-southeast-7", "route53privatedns-ca-central-1", "route53privatedns-ca-west-1", "route53privatedns-eu-central-1", "route53privatedns-eu-central-2", "route53privatedns-eu-north-1", "route53privatedns-eu-south-1", "route53privatedns-eu-south-2", "route53privatedns-eu-west-1", "route53privatedns-eu-west-2", "route53privatedns-eu-west-3", "route53privatedns-il-central-1", "route53privatedns-me-central-1", "route53privatedns-me-south-1", "route53privatedns-mx-central-1", "route53privatedns-sa-east-1", "route53privatedns-us-east-1", "route53privatedns-us-east-2", "route53privatedns-us-gov-east-1", "route53privatedns-us-gov-west-1", "route53privatedns-us-west-1", "route53privatedns-us-west-2" ]) } final class AmazonRoute53Resolver: AWSNamedService, SubService { let name = "Amazon Route 53 Resolver" let ids = Set([ "route53resolver-af-south-1", "route53resolver-ap-east-1", "route53resolver-ap-east-2", "route53resolver-ap-northeast-1", "route53resolver-ap-northeast-2", "route53resolver-ap-northeast-3", "route53resolver-ap-south-1", "route53resolver-ap-south-2", "route53resolver-ap-southeast-1", "route53resolver-ap-southeast-2", "route53resolver-ap-southeast-3", "route53resolver-ap-southeast-4", "route53resolver-ap-southeast-5", "route53resolver-ap-southeast-6", "route53resolver-ap-southeast-7", "route53resolver-ca-central-1", "route53resolver-ca-west-1", "route53resolver-eu-central-1", "route53resolver-eu-central-2", "route53resolver-eu-north-1", "route53resolver-eu-south-1", "route53resolver-eu-south-2", "route53resolver-eu-west-1", "route53resolver-eu-west-2", "route53resolver-eu-west-3", "route53resolver-il-central-1", "route53resolver-me-central-1", "route53resolver-me-south-1", "route53resolver-mx-central-1", "route53resolver-sa-east-1", "route53resolver-us-east-1", "route53resolver-us-east-2", "route53resolver-us-gov-east-1", "route53resolver-us-gov-west-1", "route53resolver-us-west-1", "route53resolver-us-west-2" ]) } final class AmazonS3ReplicationTimeControl: AWSNamedService, SubService { let name = "Amazon S3 Replication Time Control" let ids = Set([ "s3rtc-af-south-1", "s3rtc-ap-east-1", "s3rtc-ap-northeast-1", "s3rtc-ap-northeast-2", "s3rtc-ap-northeast-3", "s3rtc-ap-south-1", "s3rtc-ap-south-2", "s3rtc-ap-southeast-1", "s3rtc-ap-southeast-2", "s3rtc-ap-southeast-3", "s3rtc-ap-southeast-4", "s3rtc-ap-southeast-5", "s3rtc-ca-central-1", "s3rtc-ca-west-1", "s3rtc-eu-central-1", "s3rtc-eu-central-2", "s3rtc-eu-north-1", "s3rtc-eu-south-1", "s3rtc-eu-south-2", "s3rtc-eu-west-1", "s3rtc-eu-west-2", "s3rtc-eu-west-3", "s3rtc-il-central-1", "s3rtc-me-central-1", "s3rtc-me-south-1", "s3rtc-sa-east-1", "s3rtc-us-east-1", "s3rtc-us-east-2", "s3rtc-us-west-1", "s3rtc-us-west-2" ]) } final class AmazonSageMaker: AWSNamedService, SubService { let name = "Amazon SageMaker" let ids = Set([ "sagemaker-af-south-1", "sagemaker-ap-east-1", "sagemaker-ap-east-2", "sagemaker-ap-northeast-1", "sagemaker-ap-northeast-2", "sagemaker-ap-northeast-3", "sagemaker-ap-south-1", "sagemaker-ap-south-2", "sagemaker-ap-southeast-1", "sagemaker-ap-southeast-2", "sagemaker-ap-southeast-3", "sagemaker-ap-southeast-4", "sagemaker-ap-southeast-5", "sagemaker-ap-southeast-6", "sagemaker-ap-southeast-7", "sagemaker-ca-central-1", "sagemaker-ca-west-1", "sagemaker-eu-central-1", "sagemaker-eu-central-2", "sagemaker-eu-north-1", "sagemaker-eu-south-1", "sagemaker-eu-south-2", "sagemaker-eu-west-1", "sagemaker-eu-west-2", "sagemaker-eu-west-3", "sagemaker-il-central-1", "sagemaker-me-central-1", "sagemaker-me-south-1", "sagemaker-mx-central-1", "sagemaker-sa-east-1", "sagemaker-us-east-1", "sagemaker-us-east-2", "sagemaker-us-gov-east-1", "sagemaker-us-gov-west-1", "sagemaker-us-west-1", "sagemaker-us-west-2" ]) } final class AmazonSecurityLake: AWSNamedService, SubService { let name = "Amazon Security Lake" let ids = Set([ "securitylake-ap-northeast-1", "securitylake-ap-northeast-2", "securitylake-ap-northeast-3", "securitylake-ap-south-1", "securitylake-ap-southeast-1", "securitylake-ap-southeast-2", "securitylake-ca-central-1", "securitylake-eu-central-1", "securitylake-eu-north-1", "securitylake-eu-west-1", "securitylake-eu-west-2", "securitylake-eu-west-3", "securitylake-sa-east-1", "securitylake-us-east-1", "securitylake-us-east-2", "securitylake-us-gov-east-1", "securitylake-us-gov-west-1", "securitylake-us-west-1", "securitylake-us-west-2" ]) } final class AmazonSimpleEmailService: AWSNamedService, SubService { let name = "Amazon Simple Email Service" let ids = Set([ "ses-af-south-1", "ses-ap-northeast-1", "ses-ap-northeast-2", "ses-ap-northeast-3", "ses-ap-south-1", "ses-ap-south-2", "ses-ap-southeast-1", "ses-ap-southeast-2", "ses-ap-southeast-3", "ses-ap-southeast-5", "ses-ca-central-1", "ses-ca-west-1", "ses-eu-central-1", "ses-eu-central-2", "ses-eu-north-1", "ses-eu-south-1", "ses-eu-west-1", "ses-eu-west-2", "ses-eu-west-3", "ses-il-central-1", "ses-me-central-1", "ses-me-south-1", "ses-sa-east-1", "ses-us-east-1", "ses-us-east-2", "ses-us-gov-east-1", "ses-us-gov-west-1", "ses-us-west-1", "ses-us-west-2" ]) } final class AmazonSimpleNotificationService: AWSNamedService, SubService { let name = "Amazon Simple Notification Service" let ids = Set([ "sns-af-south-1", "sns-ap-east-1", "sns-ap-east-2", "sns-ap-northeast-1", "sns-ap-northeast-2", "sns-ap-northeast-3", "sns-ap-south-1", "sns-ap-south-2", "sns-ap-southeast-1", "sns-ap-southeast-2", "sns-ap-southeast-3", "sns-ap-southeast-4", "sns-ap-southeast-5", "sns-ap-southeast-6", "sns-ap-southeast-7", "sns-ca-central-1", "sns-ca-west-1", "sns-eu-central-1", "sns-eu-central-2", "sns-eu-north-1", "sns-eu-south-1", "sns-eu-south-2", "sns-eu-west-1", "sns-eu-west-2", "sns-eu-west-3", "sns-il-central-1", "sns-me-central-1", "sns-me-south-1", "sns-mx-central-1", "sns-sa-east-1", "sns-us-east-1", "sns-us-east-2", "sns-us-gov-east-1", "sns-us-gov-west-1", "sns-us-west-1", "sns-us-west-2" ]) } final class AmazonSimpleQueueService: AWSNamedService, SubService { let name = "Amazon Simple Queue Service" let ids = Set([ "sqs-af-south-1", "sqs-ap-east-1", "sqs-ap-east-2", "sqs-ap-northeast-1", "sqs-ap-northeast-2", "sqs-ap-northeast-3", "sqs-ap-south-1", "sqs-ap-south-2", "sqs-ap-southeast-1", "sqs-ap-southeast-2", "sqs-ap-southeast-3", "sqs-ap-southeast-4", "sqs-ap-southeast-5", "sqs-ap-southeast-6", "sqs-ap-southeast-7", "sqs-ca-central-1", "sqs-ca-west-1", "sqs-eu-central-1", "sqs-eu-central-2", "sqs-eu-north-1", "sqs-eu-south-1", "sqs-eu-south-2", "sqs-eu-west-1", "sqs-eu-west-2", "sqs-eu-west-3", "sqs-il-central-1", "sqs-me-central-1", "sqs-me-south-1", "sqs-mx-central-1", "sqs-sa-east-1", "sqs-us-east-1", "sqs-us-east-2", "sqs-us-gov-east-1", "sqs-us-gov-west-1", "sqs-us-west-1", "sqs-us-west-2" ]) } final class AmazonSimpleStorageService: AWSNamedService, SubService { let name = "Amazon Simple Storage Service" let ids = Set([ "s3-af-south-1", "s3-ap-east-1", "s3-ap-east-2", "s3-ap-northeast-1", "s3-ap-northeast-2", "s3-ap-northeast-3", "s3-ap-south-1", "s3-ap-south-2", "s3-ap-southeast-1", "s3-ap-southeast-2", "s3-ap-southeast-3", "s3-ap-southeast-4", "s3-ap-southeast-5", "s3-ap-southeast-6", "s3-ap-southeast-7", "s3-ca-central-1", "s3-ca-west-1", "s3-eu-central-1", "s3-eu-central-2", "s3-eu-north-1", "s3-eu-south-1", "s3-eu-south-2", "s3-eu-west-1", "s3-eu-west-2", "s3-eu-west-3", "s3-il-central-1", "s3-me-central-1", "s3-me-south-1", "s3-mx-central-1", "s3-sa-east-1", "s3-us-east-1", "s3-us-east-2", "s3-us-gov-east-1", "s3-us-gov-west-1", "s3-us-west-1", "s3-us-west-2" ]) } final class AmazonSimpleWorkflowService: AWSNamedService, SubService { let name = "Amazon Simple Workflow Service" let ids = Set([ "swf-af-south-1", "swf-ap-east-1", "swf-ap-east-2", "swf-ap-northeast-1", "swf-ap-northeast-2", "swf-ap-northeast-3", "swf-ap-south-1", "swf-ap-south-2", "swf-ap-southeast-1", "swf-ap-southeast-2", "swf-ap-southeast-3", "swf-ap-southeast-4", "swf-ap-southeast-5", "swf-ap-southeast-6", "swf-ap-southeast-7", "swf-ca-central-1", "swf-ca-west-1", "swf-eu-central-1", "swf-eu-central-2", "swf-eu-north-1", "swf-eu-south-1", "swf-eu-south-2", "swf-eu-west-1", "swf-eu-west-2", "swf-eu-west-3", "swf-il-central-1", "swf-me-central-1", "swf-me-south-1", "swf-mx-central-1", "swf-sa-east-1", "swf-us-east-1", "swf-us-east-2", "swf-us-gov-east-1", "swf-us-gov-west-1", "swf-us-west-1", "swf-us-west-2" ]) } final class AmazonSimpleDB: AWSNamedService, SubService { let name = "Amazon SimpleDB" let ids = Set([ "simpledb-ap-northeast-1", "simpledb-ap-southeast-1", "simpledb-ap-southeast-2", "simpledb-eu-west-1", "simpledb-sa-east-1", "simpledb-us-east-1", "simpledb-us-west-1", "simpledb-us-west-2" ]) } final class AmazonTextract: AWSNamedService, SubService { let name = "Amazon Textract" let ids = Set([ "textract-ap-northeast-2", "textract-ap-south-1", "textract-ap-southeast-1", "textract-ap-southeast-2", "textract-ca-central-1", "textract-eu-central-1", "textract-eu-south-2", "textract-eu-west-1", "textract-eu-west-2", "textract-eu-west-3", "textract-us-east-1", "textract-us-east-2", "textract-us-gov-east-1", "textract-us-gov-west-1", "textract-us-west-1", "textract-us-west-2" ]) } final class AmazonTimestream: AWSNamedService, SubService { let name = "Amazon Timestream" let ids = Set([ "timestream-ap-northeast-1", "timestream-ap-south-1", "timestream-ap-southeast-2", "timestream-eu-central-1", "timestream-eu-west-1", "timestream-us-east-1", "timestream-us-east-2", "timestream-us-gov-west-1", "timestream-us-west-2" ]) } final class AmazonTranscribe: AWSNamedService, SubService { let name = "Amazon Transcribe" let ids = Set([ "transcribe-af-south-1", "transcribe-ap-east-1", "transcribe-ap-northeast-1", "transcribe-ap-northeast-2", "transcribe-ap-south-1", "transcribe-ap-southeast-1", "transcribe-ap-southeast-2", "transcribe-ca-central-1", "transcribe-eu-central-1", "transcribe-eu-north-1", "transcribe-eu-west-1", "transcribe-eu-west-2", "transcribe-eu-west-3", "transcribe-me-south-1", "transcribe-sa-east-1", "transcribe-us-east-1", "transcribe-us-east-2", "transcribe-us-gov-east-1", "transcribe-us-gov-west-1", "transcribe-us-west-1", "transcribe-us-west-2" ]) } final class AmazonTranslate: AWSNamedService, SubService { let name = "Amazon Translate" let ids = Set([ "translate-ap-east-1", "translate-ap-northeast-1", "translate-ap-northeast-2", "translate-ap-south-1", "translate-ap-southeast-1", "translate-ap-southeast-2", "translate-ca-central-1", "translate-eu-central-1", "translate-eu-north-1", "translate-eu-west-1", "translate-eu-west-2", "translate-eu-west-3", "translate-us-east-1", "translate-us-east-2", "translate-us-gov-west-1", "translate-us-west-1", "translate-us-west-2" ]) } final class AmazonVPCIPAddressManager: AWSNamedService, SubService { let name = "Amazon VPC IP Address Manager" let ids = Set([ "ipam-af-south-1", "ipam-ap-east-1", "ipam-ap-east-2", "ipam-ap-northeast-1", "ipam-ap-northeast-2", "ipam-ap-northeast-3", "ipam-ap-south-1", "ipam-ap-south-2", "ipam-ap-southeast-1", "ipam-ap-southeast-2", "ipam-ap-southeast-3", "ipam-ap-southeast-4", "ipam-ap-southeast-5", "ipam-ap-southeast-6", "ipam-ap-southeast-7", "ipam-ca-central-1", "ipam-ca-west-1", "ipam-eu-central-1", "ipam-eu-central-2", "ipam-eu-north-1", "ipam-eu-south-1", "ipam-eu-south-2", "ipam-eu-west-1", "ipam-eu-west-2", "ipam-eu-west-3", "ipam-il-central-1", "ipam-me-central-1", "ipam-me-south-1", "ipam-mx-central-1", "ipam-sa-east-1", "ipam-us-east-1", "ipam-us-east-2", "ipam-us-gov-east-1", "ipam-us-gov-west-1", "ipam-us-west-1", "ipam-us-west-2" ]) } final class AmazonVPCLattice: AWSNamedService, SubService { let name = "Amazon VPC Lattice" let ids = Set([ "vpclattice-af-south-1", "vpclattice-ap-east-1", "vpclattice-ap-northeast-1", "vpclattice-ap-northeast-2", "vpclattice-ap-northeast-3", "vpclattice-ap-south-1", "vpclattice-ap-south-2", "vpclattice-ap-southeast-1", "vpclattice-ap-southeast-2", "vpclattice-ap-southeast-3", "vpclattice-ap-southeast-4", "vpclattice-ca-central-1", "vpclattice-ca-west-1", "vpclattice-eu-central-1", "vpclattice-eu-central-2", "vpclattice-eu-north-1", "vpclattice-eu-south-1", "vpclattice-eu-south-2", "vpclattice-eu-west-1", "vpclattice-eu-west-2", "vpclattice-eu-west-3", "vpclattice-me-central-1", "vpclattice-me-south-1", "vpclattice-sa-east-1", "vpclattice-us-east-1", "vpclattice-us-east-2", "vpclattice-us-west-1", "vpclattice-us-west-2" ]) } final class AmazonVerifiedPermissions: AWSNamedService, SubService { let name = "Amazon Verified Permissions" let ids = Set([ "verifiedpermissions-af-south-1", "verifiedpermissions-ap-east-1", "verifiedpermissions-ap-east-2", "verifiedpermissions-ap-northeast-1", "verifiedpermissions-ap-northeast-2", "verifiedpermissions-ap-northeast-3", "verifiedpermissions-ap-south-1", "verifiedpermissions-ap-south-2", "verifiedpermissions-ap-southeast-1", "verifiedpermissions-ap-southeast-2", "verifiedpermissions-ap-southeast-3", "verifiedpermissions-ap-southeast-4", "verifiedpermissions-ap-southeast-5", "verifiedpermissions-ap-southeast-6", "verifiedpermissions-ap-southeast-7", "verifiedpermissions-ca-central-1", "verifiedpermissions-ca-west-1", "verifiedpermissions-eu-central-1", "verifiedpermissions-eu-central-2", "verifiedpermissions-eu-north-1", "verifiedpermissions-eu-south-1", "verifiedpermissions-eu-south-2", "verifiedpermissions-eu-west-1", "verifiedpermissions-eu-west-2", "verifiedpermissions-eu-west-3", "verifiedpermissions-il-central-1", "verifiedpermissions-me-central-1", "verifiedpermissions-me-south-1", "verifiedpermissions-mx-central-1", "verifiedpermissions-sa-east-1", "verifiedpermissions-us-east-1", "verifiedpermissions-us-east-2", "verifiedpermissions-us-gov-east-1", "verifiedpermissions-us-gov-west-1", "verifiedpermissions-us-west-1", "verifiedpermissions-us-west-2" ]) } final class AmazonVirtualPrivateCloud: AWSNamedService, SubService { let name = "Amazon Virtual Private Cloud" let ids = Set([ "vpc-af-south-1", "vpc-ap-east-1", "vpc-ap-east-2", "vpc-ap-northeast-1", "vpc-ap-northeast-2", "vpc-ap-northeast-3", "vpc-ap-south-1", "vpc-ap-south-2", "vpc-ap-southeast-1", "vpc-ap-southeast-2", "vpc-ap-southeast-3", "vpc-ap-southeast-4", "vpc-ap-southeast-5", "vpc-ap-southeast-6", "vpc-ap-southeast-7", "vpc-ca-central-1", "vpc-ca-west-1", "vpc-eu-central-1", "vpc-eu-central-2", "vpc-eu-north-1", "vpc-eu-south-1", "vpc-eu-south-2", "vpc-eu-west-1", "vpc-eu-west-2", "vpc-eu-west-3", "vpc-il-central-1", "vpc-me-central-1", "vpc-me-south-1", "vpc-mx-central-1", "vpc-sa-east-1", "vpc-us-east-1", "vpc-us-east-2", "vpc-us-gov-east-1", "vpc-us-gov-west-1", "vpc-us-west-1", "vpc-us-west-2" ]) } final class AmazonWorkMail: AWSNamedService, SubService { let name = "Amazon WorkMail" let ids = Set([ "workmail-eu-west-1", "workmail-us-east-1", "workmail-us-west-2" ]) } final class AmazonWorkSpaces: AWSNamedService, SubService { let name = "Amazon WorkSpaces" let ids = Set([ "workspaces-af-south-1", "workspaces-ap-northeast-1", "workspaces-ap-northeast-2", "workspaces-ap-south-1", "workspaces-ap-southeast-1", "workspaces-ap-southeast-2", "workspaces-ca-central-1", "workspaces-eu-central-1", "workspaces-eu-west-1", "workspaces-eu-west-2", "workspaces-eu-west-3", "workspaces-il-central-1", "workspaces-sa-east-1", "workspaces-us-east-1", "workspaces-us-gov-east-1", "workspaces-us-gov-west-1", "workspaces-us-west-2" ]) } final class AmazonWorkSpacesApplications: AWSNamedService, SubService { let name = "Amazon WorkSpaces Applications" let ids = Set([ "appstream2-ap-northeast-1", "appstream2-ap-northeast-2", "appstream2-ap-south-1", "appstream2-ap-southeast-1", "appstream2-ap-southeast-2", "appstream2-ap-southeast-5", "appstream2-ca-central-1", "appstream2-eu-central-1", "appstream2-eu-south-1", "appstream2-eu-south-2", "appstream2-eu-west-1", "appstream2-eu-west-2", "appstream2-eu-west-3", "appstream2-il-central-1", "appstream2-sa-east-1", "appstream2-us-east-1", "appstream2-us-east-2", "appstream2-us-gov-east-1", "appstream2-us-gov-west-1", "appstream2-us-west-2" ]) } final class AmazonWorkSpacesSecureBrowser: AWSNamedService, SubService { let name = "Amazon WorkSpaces Secure Browser" let ids = Set([ "workspacesweb-ap-northeast-1", "workspacesweb-ap-south-1", "workspacesweb-ap-southeast-1", "workspacesweb-ap-southeast-2", "workspacesweb-ca-central-1", "workspacesweb-eu-central-1", "workspacesweb-eu-west-1", "workspacesweb-eu-west-2", "workspacesweb-us-east-1", "workspacesweb-us-west-2" ]) } final class AmazonWorkSpacesThinClient: AWSNamedService, SubService { let name = "Amazon WorkSpaces Thin Client" let ids = Set([ "thinclient-ap-south-1", "thinclient-ca-central-1", "thinclient-eu-central-1", "thinclient-eu-west-1", "thinclient-eu-west-2", "thinclient-us-east-1", "thinclient-us-west-2" ]) } ================================================ FILE: stts/Services/Generated/AdobeServices.swift ================================================ // This file is generated by generate_adobe_services.swift and should not be modified manually. // swiftlint:disable superfluous_disable_command type_name import Foundation final class AdobeAccountManagement: AdobeServices, SubService { let name = "Adobe Account Management" let id = "503498" } final class AdobeAcrobat: AdobeDocumentCloud, SubService { let name = "Adobe Acrobat" let id = "512699" } final class AdobeAcrobatServices: AdobeDocumentCloud, SubService { let name = "Adobe Acrobat Services" let id = "503500" } final class AdobeAcrobatSign: AdobeDocumentCloud, SubService { let name = "Adobe Acrobat Sign" let id = "503494" } final class AdobeAdministrativeConsoles: AdobeServices, SubService { let name = "Adobe Administrative Consoles" let id = "503466" } final class AdobeAdvertising: AdobeExperienceCloud, SubService { let name = "Adobe Advertising" let id = "503468" } final class AdobeAero: AdobeCreativeCloud, SubService { let name = "Adobe Aero" let id = "503511" } final class AdobeAIAssistant: AdobeExperiencePlatform, SubService { let name = "Adobe AI Assistant" let id = "568624" } final class AdobeAnalytics: AdobeExperienceCloud, SubService { let name = "Adobe Analytics" let id = "503467" } final class AdobeAudienceManager: AdobeExperienceCloud, SubService { let name = "Adobe Audience Manager" let id = "503486" } final class AdobeBrandConcierge: AdobeExperienceCloud, SubService { let name = "Adobe Brand Concierge" let id = "594942" } final class AdobeBridge: AdobeCreativeCloud, SubService { let name = "Adobe Bridge" let id = "546687" } final class AdobeCampaign: AdobeExperienceCloud, SubService { let name = "Adobe Campaign" let id = "503475" } final class AdobeCapture: AdobeCreativeCloud, SubService { let name = "Adobe Capture" let id = "503519" } final class AdobeCCCommunity: AdobeCreativeCloud, SubService { let name = "Adobe CC Community" let id = "503508" } final class AdobeColor: AdobeCreativeCloud, SubService { let name = "Adobe Color" let id = "503471" } final class AdobeCommerce: AdobeExperienceCloud, SubService { let name = "Adobe Commerce" let id = "503473" } final class AdobeConnect: AdobeServices, SubService { let name = "Adobe Connect" let id = "503474" } final class AdobeContentAuthenticity: AdobeServices, SubService { let name = "Adobe Content Authenticity" let id = "559133" } final class AdobeCreativeCloudAll: AdobeCreativeCloud, ServiceCategory { let categoryName = "Adobe Creative Cloud" let subServiceSuperclass: AnyObject.Type = BaseAdobeCreativeCloud.self let name = "Adobe Creative Cloud (All)" let id = "503459" } final class AdobeCreativeCloudApplications: AdobeCreativeCloud, SubService { let name = "Adobe Creative Cloud Applications" let id = "503492" } final class AdobeCreativeCloudLibraries: AdobeCreativeCloud, SubService { let name = "Adobe Creative Cloud Libraries" let id = "503513" } final class AdobeCreativeCloudNotifications: AdobeCreativeCloud, SubService { let name = "Adobe Creative Cloud Notifications" let id = "503517" } final class AdobeCreativeCloudSharingAndCommenting: AdobeCreativeCloud, SubService { let name = "Adobe Creative Cloud Sharing and Commenting" let id = "503505" } final class AdobeCreativeCloudStorage: AdobeCreativeCloud, SubService { let name = "Adobe Creative Cloud Storage" let id = "503521" } final class AdobeCreativeCloudSync: AdobeCreativeCloud, SubService { let name = "Adobe Creative Cloud Sync" let id = "503523" } final class AdobeCreativeCloudWebsite: AdobeCreativeCloud, SubService { let name = "Adobe Creative Cloud Website" let id = "503522" } final class AdobeCrossCloudCapabilities: AdobeExperienceCloud, SubService { let name = "Adobe Cross-Cloud Capabilities" let id = "503484" } final class AdobeCustomerJourneyAnalytics: AdobeExperienceCloud, SubService { let name = "Adobe Customer Journey Analytics" let id = "503485" } final class AdobeCustomerSupport: AdobeServices, SubService { let name = "Adobe Customer Support" let id = "558202" } final class AdobeDataFoundation: AdobeExperiencePlatform, SubService { let name = "Adobe Data Foundation" let id = "503462" } final class AdobeDataScienceWorkspace: AdobeExperiencePlatform, SubService { let name = "Adobe Data Science Workspace" let id = "503463" } final class AdobeDeveloperPlatform: AdobeServices, SubService { let name = "Adobe Developer Platform" let id = "503495" } final class AdobeDigitalVideoAndAudio: AdobeCreativeCloud, SubService { let name = "Adobe Digital Video & Audio" let id = "582550" } final class AdobeDimension: AdobeCreativeCloud, SubService { let name = "Adobe Dimension" let id = "503503" } final class AdobeDocumentCloudAll: AdobeDocumentCloud, ServiceCategory { let categoryName = "Adobe Document Cloud" let subServiceSuperclass: AnyObject.Type = BaseAdobeDocumentCloud.self let name = "Adobe Document Cloud (All)" let id = "503457" } final class AdobeExperienceCloudAll: AdobeExperienceCloud, ServiceCategory { let categoryName = "Adobe Experience Cloud" let subServiceSuperclass: AnyObject.Type = BaseAdobeExperienceCloud.self let name = "Adobe Experience Cloud (All)" let id = "503461" } final class AdobeExperienceCloudHome: AdobeExperienceCloud, SubService { let name = "Adobe Experience Cloud Home" let id = "503464" } final class AdobeExperienceLeague: AdobeServices, SubService { let name = "Adobe Experience League" let id = "503479" } final class AdobeExperienceManager: AdobeExperienceCloud, SubService { let name = "Adobe Experience Manager" let id = "503470" } final class AdobeExperienceManagerAsACloudService: AdobeExperienceCloud, SubService { let name = "Adobe Experience Manager as a Cloud Service" let id = "503489" } final class AdobeExperiencePlatformAll: AdobeExperiencePlatform, ServiceCategory { let categoryName = "Adobe Experience Platform" let subServiceSuperclass: AnyObject.Type = BaseAdobeExperiencePlatform.self let name = "Adobe Experience Platform (All)" let id = "503460" } final class AdobeExpress: AdobeCreativeCloud, SubService { let name = "Adobe Express" let id = "503465" } final class AdobeFirefly: AdobeCreativeCloud, SubService { let name = "Adobe Firefly" let id = "536716" } final class AdobeFonts: AdobeCreativeCloud, SubService { let name = "Adobe Fonts" let id = "503501" } final class AdobeFresco: AdobeCreativeCloud, SubService { let name = "Adobe Fresco" let id = "503469" } final class AdobeGenStudioForPerformanceMarketing: AdobeExperienceCloud, SubService { let name = "Adobe GenStudio for Performance Marketing" let id = "554521" } final class AdobeIllustrator: AdobeCreativeCloud, SubService { let name = "Adobe Illustrator" let id = "503524" } final class AdobeImageService: AdobeServices, SubService { let name = "Adobe Image Service" let id = "503512" } final class AdobeInDesign: AdobeCreativeCloud, SubService { let name = "Adobe InDesign" let id = "503502" } final class AdobeInDesignAPI: AdobeCreativeCloud, SubService { let name = "Adobe InDesign API" let id = "572928" } final class AdobeIntelligentServices: AdobeExperienceCloud, SubService { let name = "Adobe Intelligent Services" let id = "503480" } final class AdobeInviteAccept: AdobeServices, SubService { let name = "Adobe Invite Accept" let id = "503499" } final class AdobeJourneyOptimizer: AdobeExperienceCloud, SubService { let name = "Adobe Journey Optimizer" let id = "503488" } final class AdobeJourneyOptimizerB2B: AdobeExperienceCloud, SubService { let name = "Adobe Journey Optimizer B2B" let id = "552633" } final class AdobeLearningManager: AdobeServices, SubService { let name = "Adobe Learning Manager" let id = "503520" } final class AdobeLightroom: AdobeCreativeCloud, SubService { let name = "Adobe Lightroom" let id = "503487" } final class AdobeLive: AdobeCreativeCloud, SubService { let name = "Adobe Live" let id = "503514" } final class AdobeLLMOptimizer: AdobeExperienceCloud, SubService { let name = "Adobe LLM Optimizer" let id = "595270" } final class AdobeMarketoEngage: AdobeExperienceCloud, SubService { let name = "Adobe Marketo Engage" let id = "503491" } final class AdobeMixamo: AdobeCreativeCloud, SubService { let name = "Adobe Mixamo" let id = "503585" } final class AdobePhotoshop: AdobeCreativeCloud, SubService { let name = "Adobe Photoshop" let id = "503493" } final class AdobePlatformCoreServices: AdobeExperiencePlatform, SubService { let name = "Adobe Platform Core Services" let id = "503481" } final class AdobePremierePro: AdobeCreativeCloud, SubService { let name = "Adobe Premiere Pro" let id = "503509" } final class AdobePremiereRush: AdobeCreativeCloud, SubService { let name = "Adobe Premiere Rush" let id = "503506" } final class AdobePrimetime: AdobeExperienceCloud, SubService { let name = "Adobe Primetime" let id = "503478" } final class AdobeQueryService: AdobeExperiencePlatform, SubService { let name = "Adobe Query Service" let id = "503482" } final class AdobeRealTimeCDP: AdobeExperienceCloud, SubService { let name = "Adobe Real Time CDP" let id = "533248" } final class AdobeResellerConsole: AdobeServices, SubService { let name = "Adobe Reseller Console" let id = "503497" } final class AdobeSearch: AdobeServices, SubService { let name = "Adobe Search" let id = "503507" } final class AdobeServicesAll: AdobeServices, ServiceCategory { let categoryName = "Adobe Services" let subServiceSuperclass: AnyObject.Type = BaseAdobeServices.self let name = "Adobe Services (All)" let id = "503458" } final class AdobeSignIn: AdobeServices, SubService { let name = "Adobe Sign In" let id = "503525" } final class AdobeStatusServiceProbe: AdobeServices, SubService { let name = "Adobe Status Service Probe" let id = "554089" } final class AdobeSubstance: AdobeCreativeCloud, SubService { let name = "Adobe Substance" let id = "503518" } final class AdobeSupport: AdobeServices, SubService { let name = "Adobe Support" let id = "503510" } final class AdobeTarget: AdobeExperienceCloud, SubService { let name = "Adobe Target" let id = "503476" } final class AdobeWorkfront: AdobeExperienceCloud, SubService { let name = "Adobe Workfront" let id = "503490" } final class AdobeXD: AdobeCreativeCloud, SubService { let name = "Adobe XD" let id = "503477" } ================================================ FILE: stts/Services/Generated/AppleServices.swift ================================================ // This file is generated by generate_apple_services.swift and should not be modified manually. // swiftlint:disable superfluous_disable_command type_name import Foundation final class AppleAll: Apple, ServiceCategory { let categoryName = "Apple" let subServiceSuperclass: AnyObject.Type = BaseApple.self let name = "Apple (All)" let serviceName = "*" } final class AppleAppStore: Apple, SubService { let name = "Apple App Store" let serviceName = "App Store" } final class AppleAccount: Apple, SubService { let name = "Apple Account" let serviceName = "Apple Account" } final class AppleAccountCard: Apple, SubService { let name = "Apple Account Card" let serviceName = "Apple Account Card" } final class AppleArcade: Apple, SubService { let name = "Apple Arcade" let serviceName = "Apple Arcade" } final class AppleBooks: Apple, SubService { let name = "Apple Books" let serviceName = "Apple Books" } final class AppleBusinessEssentials: Apple, SubService { let name = "Apple Business Essentials" let serviceName = "Apple Business Essentials" } final class AppleBusinessManager: Apple, SubService { let name = "Apple Business Manager" let serviceName = "Apple Business Manager" } final class AppleCard: Apple, SubService { let name = "Apple Card" let serviceName = "Apple Card" } final class AppleCash: Apple, SubService { let name = "Apple Cash" let serviceName = "Apple Cash" } final class AppleFitness: Apple, SubService { let name = "Apple Fitness+" let serviceName = "Apple Fitness+" } final class AppleInvites: Apple, SubService { let name = "Apple Invites" let serviceName = "Apple Invites" } final class AppleMessagesForBusiness: Apple, SubService { let name = "Apple Messages for Business" let serviceName = "Apple Messages for Business" } final class AppleMusic: Apple, SubService { let name = "Apple Music" let serviceName = "Apple Music" } final class AppleMusicClassical: Apple, SubService { let name = "Apple Music Classical" let serviceName = "Apple Music Classical" } final class AppleMusicRadio: Apple, SubService { let name = "Apple Music radio" let serviceName = "Apple Music radio" } final class AppleMusicSubscriptions: Apple, SubService { let name = "Apple Music Subscriptions" let serviceName = "Apple Music Subscriptions" } final class AppleOnlineStore: Apple, SubService { let name = "Apple Online Store" let serviceName = "Apple Online Store" } final class ApplePay: Apple, SubService { let name = "Apple Pay" let serviceName = "Apple Pay" } final class AppleSchoolManager: Apple, SubService { let name = "Apple School Manager" let serviceName = "Apple School Manager" } final class AppleSports: Apple, SubService { let name = "Apple Sports" let serviceName = "Apple Sports" } final class AppleTVChannels: Apple, SubService { let name = "Apple TV Channels" let serviceName = "Apple TV Channels" } final class AppleTV: Apple, SubService { let name = "Apple TV" let serviceName = "Apple TV" } final class AppleCareOnDevice: Apple, SubService { let name = "AppleCare on Device" let serviceName = "AppleCare on Device" } final class AppleAudiobooks: Apple, SubService { let name = "Apple Audiobooks" let serviceName = "Audiobooks" } final class AppleBusinessConnect: Apple, SubService { let name = "Apple BusinessConnect" let serviceName = "BusinessConnect" } final class AppleDictation: Apple, SubService { let name = "Apple Dictation" let serviceName = "Dictation" } final class AppleFaceTime: Apple, SubService { let name = "Apple FaceTime" let serviceName = "FaceTime" } final class AppleFindMy: Apple, SubService { let name = "Apple Find My" let serviceName = "Find My" } final class AppleGameCenter: Apple, SubService { let name = "Apple Game Center" let serviceName = "Game Center" } final class AppleGlobalServiceExchange: Apple, SubService { let name = "Apple Global Service Exchange" let serviceName = "Global Service Exchange" } final class AppleHealthSharingWithProvider: Apple, SubService { let name = "Apple Health sharing with provider" let serviceName = "Health sharing with provider" } final class AppleHomeKit: Apple, SubService { let name = "Apple HomeKit" let serviceName = "HomeKit" } final class AppleHomeKitSecureVideo: Apple, SubService { let name = "Apple HomeKit Secure Video" let serviceName = "HomeKit Secure Video" } final class AppleICloudAccountAndSignIn: Apple, SubService { let name = "Apple iCloud Account & Sign In" let serviceName = "iCloud Account & Sign In" } final class AppleICloudBackup: Apple, SubService { let name = "Apple iCloud Backup" let serviceName = "iCloud Backup" } final class AppleICloudBookmarksAndTabs: Apple, SubService { let name = "Apple iCloud Bookmarks & Tabs" let serviceName = "iCloud Bookmarks & Tabs" } final class AppleICloudCalendar: Apple, SubService { let name = "Apple iCloud Calendar" let serviceName = "iCloud Calendar" } final class AppleICloudContacts: Apple, SubService { let name = "Apple iCloud Contacts" let serviceName = "iCloud Contacts" } final class AppleICloudDrive: Apple, SubService { let name = "Apple iCloud Drive" let serviceName = "iCloud Drive" } final class AppleICloudKeychain: Apple, SubService { let name = "Apple iCloud Keychain" let serviceName = "iCloud Keychain" } final class AppleICloudMail: Apple, SubService { let name = "Apple iCloud Mail" let serviceName = "iCloud Mail" } final class AppleICloudNotes: Apple, SubService { let name = "Apple iCloud Notes" let serviceName = "iCloud Notes" } final class AppleICloudPrivateRelay: Apple, SubService { let name = "Apple iCloud Private Relay" let serviceName = "iCloud Private Relay" } final class AppleICloudReminders: Apple, SubService { let name = "Apple iCloud Reminders" let serviceName = "iCloud Reminders" } final class AppleICloudStorageUpgrades: Apple, SubService { let name = "Apple iCloud Storage Upgrades" let serviceName = "iCloud Storage Upgrades" } final class AppleICloudWebAppsICloudcom: Apple, SubService { let name = "Apple iCloud Web Apps (iCloud.com)" let serviceName = "iCloud Web Apps (iCloud.com)" } final class AppleIdentityDriversLicenseOrID: Apple, SubService { let name = "Apple Identity - Drivers License or ID" let serviceName = "Identity - Drivers License or ID" } final class AppleIMessage: Apple, SubService { let name = "Apple iMessage" let serviceName = "iMessage" } final class AppleIOSDeviceActivation: Apple, SubService { let name = "Apple iOS Device Activation" let serviceName = "iOS Device Activation" } final class AppleITunesMatch: Apple, SubService { let name = "Apple iTunes Match" let serviceName = "iTunes Match" } final class AppleITunesStore: Apple, SubService { let name = "Apple iTunes Store" let serviceName = "iTunes Store" } final class AppleIWorkCollaboration: Apple, SubService { let name = "Apple iWork Collaboration" let serviceName = "iWork Collaboration" } final class AppleIWorkForICloud: Apple, SubService { let name = "Apple iWork for iCloud" let serviceName = "iWork for iCloud" } final class AppleMacAppStore: Apple, SubService { let name = "Apple Mac App Store" let serviceName = "Mac App Store" } final class AppleMacOSSoftwareUpdate: Apple, SubService { let name = "Apple macOS Software Update" let serviceName = "macOS Software Update" } final class AppleMailDrop: Apple, SubService { let name = "Apple Mail Drop" let serviceName = "Mail Drop" } final class AppleMapsDisplay: Apple, SubService { let name = "Apple Maps Display" let serviceName = "Maps Display" } final class AppleMapsRoutingAndNavigation: Apple, SubService { let name = "Apple Maps Routing & Navigation" let serviceName = "Maps Routing & Navigation" } final class AppleMapsSearch: Apple, SubService { let name = "Apple Maps Search" let serviceName = "Maps Search" } final class AppleMapsTraffic: Apple, SubService { let name = "Apple Maps Traffic" let serviceName = "Maps Traffic" } final class AppleNews: Apple, SubService { let name = "Apple News" let serviceName = "News" } final class ApplePhotos: Apple, SubService { let name = "Apple Photos" let serviceName = "Photos" } final class ApplePodcasts: Apple, SubService { let name = "Apple Podcasts" let serviceName = "Podcasts" } final class ApplePrivateCloudCompute: Apple, SubService { let name = "Apple Private Cloud Compute" let serviceName = "Private Cloud Compute" } final class AppleRadio: Apple, SubService { let name = "Apple Radio" let serviceName = "Radio" } final class AppleSchooltime: Apple, SubService { let name = "Apple Schooltime" let serviceName = "Schooltime" } final class AppleSchoolwork: Apple, SubService { let name = "Apple Schoolwork" let serviceName = "Schoolwork" } final class AppleScreenTime: Apple, SubService { let name = "Apple Screen Time" let serviceName = "Screen Time" } final class AppleSignInWithApple: Apple, SubService { let name = "Apple Sign in with Apple" let serviceName = "Sign in with Apple" } final class AppleSiri: Apple, SubService { let name = "Apple Siri" let serviceName = "Siri" } final class AppleSpotlightSuggestions: Apple, SubService { let name = "Apple Spotlight suggestions" let serviceName = "Spotlight suggestions" } final class AppleStocks: Apple, SubService { let name = "Apple Stocks" let serviceName = "Stocks" } final class AppleSubscriptionPurchase: Apple, SubService { let name = "Apple Subscription Purchase" let serviceName = "Subscription Purchase" } final class AppleTVProvider: Apple, SubService { let name = "Apple TV Provider" let serviceName = "TV Provider" } final class AppleVisionOSAppStore: Apple, SubService { let name = "Apple visionOS App Store" let serviceName = "visionOS App Store" } final class AppleVolumePurchaseProgram: Apple, SubService { let name = "Apple Volume Purchase Program" let serviceName = "Volume Purchase Program" } final class AppleWalkieTalkie: Apple, SubService { let name = "Apple Walkie-Talkie" let serviceName = "Walkie-Talkie" } final class AppleWallet: Apple, SubService { let name = "Apple Wallet" let serviceName = "Wallet" } final class AppleWeather: Apple, SubService { let name = "Apple Weather" let serviceName = "Weather" } final class AppleDeveloperAll: AppleDeveloper, ServiceCategory { let categoryName = "Apple Developer" let subServiceSuperclass: AnyObject.Type = BaseAppleDeveloper.self let name = "Apple Developer (All)" let serviceName = "*" } final class AppleAccountDeveloper: AppleDeveloper, SubService { let name = "Apple Account (Developer)" let serviceName = "Account" } final class AppleAPNS: AppleDeveloper, SubService { let name = "Apple APNS" let serviceName = "APNS" } final class AppleAPNSSandbox: AppleDeveloper, SubService { let name = "Apple APNS Sandbox" let serviceName = "APNS Sandbox" } final class AppleAppAttest: AppleDeveloper, SubService { let name = "Apple App Attest" let serviceName = "App Attest" } final class AppleAppStoreAdvancedCommerceAPI: AppleDeveloper, SubService { let name = "Apple App Store - Advanced Commerce API" let serviceName = "App Store - Advanced Commerce API" } final class AppleAppStoreInAppPurchases: AppleDeveloper, SubService { let name = "Apple App Store - In-App Purchases" let serviceName = "App Store - In-App Purchases" } final class AppleAppStoreReceiptVerification: AppleDeveloper, SubService { let name = "Apple App Store - Receipt Verification" let serviceName = "App Store - Receipt Verification" } final class AppleAppStoreSandbox: AppleDeveloper, SubService { let name = "Apple App Store - Sandbox" let serviceName = "App Store - Sandbox" } final class AppleAppStoreServerAPIs: AppleDeveloper, SubService { let name = "Apple App Store - Server APIs" let serviceName = "App Store - Server APIs" } final class AppleAppStoreServerNotifications: AppleDeveloper, SubService { let name = "Apple App Store - Server Notifications" let serviceName = "App Store - Server Notifications" } final class AppleAppStoreAutomaticAppUpdates: AppleDeveloper, SubService { let name = "Apple App Store Automatic App Updates" let serviceName = "App Store Automatic App Updates" } final class AppleAppStoreConnect: AppleDeveloper, SubService { let name = "Apple App Store Connect" let serviceName = "App Store Connect" } final class AppleAppStoreConnectAnalytics: AppleDeveloper, SubService { let name = "Apple App Store Connect - Analytics" let serviceName = "App Store Connect - Analytics" } final class AppleAppStoreConnectAppProcessing: AppleDeveloper, SubService { let name = "Apple App Store Connect - App Processing " let serviceName = "App Store Connect - App Processing " } final class AppleAppStoreConnectAppUpload: AppleDeveloper, SubService { let name = "Apple App Store Connect - App Upload" let serviceName = "App Store Connect - App Upload" } final class AppleAppStoreConnectSalesAndTrends: AppleDeveloper, SubService { let name = "Apple App Store Connect - Sales and Trends" let serviceName = "App Store Connect - Sales and Trends" } final class AppleAppStoreConnectTestFlight: AppleDeveloper, SubService { let name = "Apple App Store Connect - TestFlight" let serviceName = "App Store Connect - TestFlight" } final class AppleAppStoreConnectAPI: AppleDeveloper, SubService { let name = "Apple App Store Connect API" let serviceName = "App Store Connect API" } final class AppleDeveloperForums: AppleDeveloper, SubService { let name = "Apple Developer Forums" let serviceName = "Apple Developer Forums" } final class AppleMapsAPI: AppleDeveloper, SubService { let name = "Apple Maps API" let serviceName = "Apple Maps API" } final class AppleMusicAPI: AppleDeveloper, SubService { let name = "Apple Music API" let serviceName = "Apple Music API" } final class AppleMusicConnect: AppleDeveloper, SubService { let name = "Apple Music Connect" let serviceName = "Apple Music Connect" } final class AppleMusicForArtists: AppleDeveloper, SubService { let name = "Apple Music for Artists" let serviceName = "Apple Music for Artists" } final class AppleNewsAPI: AppleDeveloper, SubService { let name = "Apple News API" let serviceName = "Apple News API" } final class ApplePayDeveloperApplePayDemo: AppleDeveloper, SubService { let name = "Apple Pay Developer | Apple Pay Demo" let serviceName = "Apple Pay Developer | Apple Pay Demo" } final class ApplePayProductionInstance: AppleDeveloper, SubService { let name = "Apple Pay Production Instance" let serviceName = "Apple Pay Production Instance" } final class ApplePaySandboxInstance: AppleDeveloper, SubService { let name = "Apple Pay Sandbox Instance" let serviceName = "Apple Pay Sandbox Instance" } final class ApplePodcastsConnect: AppleDeveloper, SubService { let name = "Apple Podcasts Connect" let serviceName = "Apple Podcasts Connect" } final class AppleCertificatesIdentifiersAndProfiles: AppleDeveloper, SubService { let name = "Apple Certificates, Identifiers & Profiles" let serviceName = "Certificates, Identifiers & Profiles" } final class AppleCloudKitConsole: AppleDeveloper, SubService { let name = "Apple CloudKit Console" let serviceName = "CloudKit Console" } final class AppleCloudKitDatabase: AppleDeveloper, SubService { let name = "Apple CloudKit Database" let serviceName = "CloudKit Database" } final class AppleCodelevelSupport: AppleDeveloper, SubService { let name = "Apple Code-level Support" let serviceName = "Code-level Support" } final class AppleContactUs: AppleDeveloper, SubService { let name = "Apple Contact Us" let serviceName = "Contact Us" } final class AppleDeveloperDocumentation: AppleDeveloper, SubService { let name = "Apple Developer Documentation" let serviceName = "Developer Documentation" } final class AppleDeveloperIDNotaryService: AppleDeveloper, SubService { let name = "Apple Developer ID Notary Service" let serviceName = "Developer ID Notary Service" } final class AppleDeviceEnrollmentProgram: AppleDeveloper, SubService { let name = "Apple Device Enrollment Program" let serviceName = "Device Enrollment Program" } final class AppleFeedbackAssistant: AppleDeveloper, SubService { let name = "Apple Feedback Assistant" let serviceName = "Feedback Assistant" } final class AppleMapKitJSDashboard: AppleDeveloper, SubService { let name = "Apple MapKit JS Dashboard" let serviceName = "MapKit JS Dashboard" } final class AppleMFiPortal: AppleDeveloper, SubService { let name = "Apple MFi Portal" let serviceName = "MFi Portal" } final class AppleNewsPublisher: AppleDeveloper, SubService { let name = "Apple News Publisher" let serviceName = "News Publisher" } final class AppleNFCAndSEPlatform: AppleDeveloper, SubService { let name = "Apple NFC & SE Platform" let serviceName = "NFC & SE Platform" } final class AppleProgramEnrollmentAndRenewals: AppleDeveloper, SubService { let name = "Apple Program Enrollment and Renewals" let serviceName = "Program Enrollment and Renewals" } final class AppleSKAdNetwork: AppleDeveloper, SubService { let name = "Apple SKAdNetwork" let serviceName = "SKAdNetwork" } final class AppleSoftwareDownloads: AppleDeveloper, SubService { let name = "Apple Software Downloads" let serviceName = "Software Downloads" } final class AppleTapToPayOnIPhone: AppleDeveloper, SubService { let name = "Apple Tap to Pay on iPhone" let serviceName = "Tap to Pay on iPhone" } final class AppleVideos: AppleDeveloper, SubService { let name = "Apple Videos" let serviceName = "Videos" } final class AppleWeatherKit: AppleDeveloper, SubService { let name = "Apple WeatherKit" let serviceName = "WeatherKit" } final class AppleXcodeAutomaticConfiguration: AppleDeveloper, SubService { let name = "Apple Xcode Automatic Configuration" let serviceName = "Xcode Automatic Configuration" } final class AppleXcodeCloud: AppleDeveloper, SubService { let name = "Apple Xcode Cloud" let serviceName = "Xcode Cloud" } ================================================ FILE: stts/Services/Generated/AzureDevOpsServices.swift ================================================ // This file is generated by generate_azure_devops_services.swift and should not be modified manually. // swiftlint:disable superfluous_disable_command type_name import Foundation final class AzureDevOpsCoreServices: AzureDevOps, SubService { let name = "Azure DevOps Core Services" let serviceName = "Core services" } final class AzureDevOpsBoards: AzureDevOps, SubService { let name = "Azure DevOps Boards" let serviceName = "Boards" } final class AzureDevOpsRepos: AzureDevOps, SubService { let name = "Azure DevOps Repos" let serviceName = "Repos" } final class AzureDevOpsPipelines: AzureDevOps, SubService { let name = "Azure DevOps Pipelines" let serviceName = "Pipelines" } final class AzureDevOpsTestPlans: AzureDevOps, SubService { let name = "Azure DevOps Test Plans" let serviceName = "Test Plans" } final class AzureDevOpsArtifacts: AzureDevOps, SubService { let name = "Azure DevOps Artifacts" let serviceName = "Artifacts" } final class AzureDevOpsOtherServices: AzureDevOps, SubService { let name = "Azure DevOps Other Services" let serviceName = "Other services" } ================================================ FILE: stts/Services/Generated/AzureServices.swift ================================================ // This file is generated by generate_azure_services.swift and should not be modified manually. // swiftlint:disable superfluous_disable_command type_name import Foundation final class AzureAmericas: Azure, SubService { let name = "Azure Americas" let zoneIdentifier = "americas" } final class AzureEurope: Azure, SubService { let name = "Azure Europe" let zoneIdentifier = "europe" } final class AzureAsiaPacific: Azure, SubService { let name = "Azure Asia Pacific" let zoneIdentifier = "asia" } final class AzureMiddleEastAndAfrica: Azure, SubService { let name = "Azure Middle East and Africa" let zoneIdentifier = "middle-east-africa" } final class AzureGovernment: Azure, SubService { let name = "Azure Government" let zoneIdentifier = "azure-government" } final class AzureChina: Azure, SubService { let name = "Azure China" let zoneIdentifier = "azure-china" } final class AzureJio: Azure, SubService { let name = "Azure Jio" let zoneIdentifier = "jio" } ================================================ FILE: stts/Services/Generated/FirebaseServices.swift ================================================ // This file is generated by generate_google_services.swift and should not be modified manually. // swiftlint:disable superfluous_disable_command type_name import Foundation final class FirebaseABTestingBETA: FirebaseService, SubService { let name = "Firebase AB Testing (BETA)" } final class FirebaseAppCheck: FirebaseService, SubService { let name = "Firebase App Check" } final class FirebaseAppDistribution: FirebaseService, SubService { let name = "Firebase App Distribution" } final class FirebaseAppHosting: FirebaseService, SubService { let name = "Firebase App Hosting" } final class FirebaseAppIndexing: FirebaseService, SubService { let name = "Firebase App Indexing" } final class FirebaseAuthentication: FirebaseService, SubService { let name = "Firebase Authentication" } final class FirebaseCloudMessaging: FirebaseService, SubService { let name = "Firebase Cloud Messaging" } final class FirebaseConsole: FirebaseService, SubService { let name = "Firebase Console" } final class FirebaseCrashlytics: FirebaseService, SubService { let name = "Firebase Crashlytics" } final class FirebaseDataConnect: FirebaseService, SubService { let name = "Firebase Data Connect" } final class FirebaseDynamicLinks: FirebaseService, SubService { let name = "Firebase Dynamic Links" } final class FirebaseExtensions: FirebaseService, SubService { let name = "Firebase Extensions" } final class FirebaseAILogic: FirebaseService, SubService { let name = "Firebase AI Logic" } final class FirebaseStudio: FirebaseService, SubService { let name = "Firebase Studio" } final class FirebaseGeminiInFirebase: FirebaseService, SubService { let name = "Firebase Gemini in Firebase" } final class FirebaseGenkit: FirebaseService, SubService { let name = "Firebase Genkit" } final class FirebaseHosting: FirebaseService, SubService { let name = "Firebase Hosting" } final class FirebaseMachineLearningBETA: FirebaseService, SubService { let name = "Firebase Machine Learning (BETA)" } final class FirebasePerformanceMonitoring: FirebaseService, SubService { let name = "Firebase Performance Monitoring" } final class FirebaseRealtimeDatabase: FirebaseService, SubService { let name = "Firebase Realtime Database" } final class FirebaseRemoteConfig: FirebaseService, SubService { let name = "Firebase Remote Config" } final class FirebaseTestLab: FirebaseService, SubService { let name = "Firebase Test Lab" } ================================================ FILE: stts/Services/Generated/GoogleCloudPlatformServices.swift ================================================ // This file is generated by generate_google_services.swift and should not be modified manually. // swiftlint:disable superfluous_disable_command type_name import Foundation final class GoogleAccessApproval: GoogleCloudPlatform, SubService { let name = "Google Access Approval" let dashboardName = "Access Approval" } final class GoogleAccessContextManager: GoogleCloudPlatform, SubService { let name = "Google Access Context Manager" let dashboardName = "Access Context Manager" } final class GoogleAccessTransparency: GoogleCloudPlatform, SubService { let name = "Google Access Transparency" let dashboardName = "Access Transparency" } final class GoogleAgentAssist: GoogleCloudPlatform, SubService { let name = "Google Agent Assist" let dashboardName = "Agent Assist" } final class GoogleAIPlatformPrediction: GoogleCloudPlatform, SubService { let name = "Google AI Platform Prediction" let dashboardName = "AI Platform Prediction" } final class GoogleAIPlatformTraining: GoogleCloudPlatform, SubService { let name = "Google AI Platform Training" let dashboardName = "AI Platform Training" } final class GoogleAlloyDBForPostgreSQL: GoogleCloudPlatform, SubService { let name = "Google AlloyDB for PostgreSQL" let dashboardName = "AlloyDB for PostgreSQL" } final class GoogleAnthosServiceMesh: GoogleCloudPlatform, SubService { let name = "Google Anthos Service Mesh" let dashboardName = "Anthos Service Mesh" } final class GoogleAPIGateway: GoogleCloudPlatform, SubService { let name = "Google API Gateway" let dashboardName = "API Gateway" } final class GoogleApigee: GoogleCloudPlatform, SubService { let name = "Google Apigee" let dashboardName = "Apigee" } final class GoogleApigeeEdgePrivateCloud: GoogleCloudPlatform, SubService { let name = "Google Apigee Edge Private Cloud" let dashboardName = "Apigee Edge Private Cloud" } final class GoogleApigeeEdgePublicCloud: GoogleCloudPlatform, SubService { let name = "Google Apigee Edge Public Cloud" let dashboardName = "Apigee Edge Public Cloud" } final class GoogleApigeeHybrid: GoogleCloudPlatform, SubService { let name = "Google Apigee Hybrid" let dashboardName = "Apigee Hybrid" } final class GoogleApplicationIntegration: GoogleCloudPlatform, SubService { let name = "Google Application Integration" let dashboardName = "Application Integration" } final class GoogleArtifactRegistry: GoogleCloudPlatform, SubService { let name = "Google Artifact Registry" let dashboardName = "Artifact Registry" } final class GoogleAssuredWorkloads: GoogleCloudPlatform, SubService { let name = "Google Assured Workloads" let dashboardName = "Assured Workloads" } final class GoogleAutoMLNaturalLanguage: GoogleCloudPlatform, SubService { let name = "Google AutoML Natural Language" let dashboardName = "AutoML Natural Language" } final class GoogleAutoMLTables: GoogleCloudPlatform, SubService { let name = "Google AutoML Tables" let dashboardName = "AutoML Tables" } final class GoogleAutoMLTranslation: GoogleCloudPlatform, SubService { let name = "Google AutoML Translation" let dashboardName = "AutoML Translation" } final class GoogleAutoMLVideo: GoogleCloudPlatform, SubService { let name = "Google AutoML Video" let dashboardName = "AutoML Video" } final class GoogleAutoMLVision: GoogleCloudPlatform, SubService { let name = "Google AutoML Vision" let dashboardName = "AutoML Vision" } final class GoogleBackupAndDR: GoogleCloudPlatform, SubService { let name = "Google Backup and DR" let dashboardName = "Backup and DR" } final class GoogleBackupForGKE: GoogleCloudPlatform, SubService { let name = "Google Backup for GKE" let dashboardName = "Backup for GKE" } final class GoogleBareMetalSolution: GoogleCloudPlatform, SubService { let name = "Google Bare Metal Solution" let dashboardName = "Bare Metal Solution" } final class GoogleBatch: GoogleCloudPlatform, SubService { let name = "Google Batch" let dashboardName = "Batch" } final class GoogleBeyondCorpEnterprise: GoogleCloudPlatform, SubService { let name = "Google BeyondCorp Enterprise" let dashboardName = "BeyondCorp Enterprise" } final class GoogleBigQueryDataTransferService: GoogleCloudPlatform, SubService { let name = "Google BigQuery Data Transfer Service" let dashboardName = "BigQuery Data Transfer Service" } final class GoogleBinaryAuthorization: GoogleCloudPlatform, SubService { let name = "Google Binary Authorization" let dashboardName = "Binary Authorization" } final class GoogleCertificateAuthorityService: GoogleCloudPlatform, SubService { let name = "Google Certificate Authority Service" let dashboardName = "Certificate Authority Service" } final class GoogleCertificateManager: GoogleCloudPlatform, SubService { let name = "Google Certificate Manager" let dashboardName = "Certificate Manager" } final class GoogleCloudArmor: GoogleCloudPlatform, SubService { let name = "Google Cloud Armor" let dashboardName = "Cloud Armor" } final class GoogleCloudAssetInventory: GoogleCloudPlatform, SubService { let name = "Google Cloud Asset Inventory" let dashboardName = "Cloud Asset Inventory" } final class GoogleCloudBilling: GoogleCloudPlatform, SubService { let name = "Google Cloud Billing" let dashboardName = "Cloud Billing" } final class GoogleCloudBuild: GoogleCloudPlatform, SubService { let name = "Google Cloud Build" let dashboardName = "Cloud Build" } final class GoogleCloudCDN: GoogleCloudPlatform, SubService { let name = "Google Cloud CDN" let dashboardName = "Cloud CDN" } final class GoogleCloudDataFusion: GoogleCloudPlatform, SubService { let name = "Google Cloud Data Fusion" let dashboardName = "Cloud Data Fusion" } final class GoogleCloudDataLossPrevention: GoogleCloudPlatform, SubService { let name = "Google Cloud Data Loss Prevention" let dashboardName = "Cloud Data Loss Prevention" } final class GoogleCloudDomains: GoogleCloudPlatform, SubService { let name = "Google Cloud Domains" let dashboardName = "Cloud Domains" } final class GoogleCloudEndpoints: GoogleCloudPlatform, SubService { let name = "Google Cloud Endpoints" let dashboardName = "Cloud Endpoints" } final class GoogleCloudExternalKeyManager: GoogleCloudPlatform, SubService { let name = "Google Cloud External Key Manager" let dashboardName = "Cloud External Key Manager" } final class GoogleCloudFilestore: GoogleCloudPlatform, SubService { let name = "Google Cloud Filestore" let dashboardName = "Cloud Filestore" } final class GoogleCloudFirestore: GoogleCloudPlatform, SubService { let name = "Google Cloud Firestore" let dashboardName = "Cloud Firestore" } final class GoogleCloudHSM: GoogleCloudPlatform, SubService { let name = "Google Cloud HSM" let dashboardName = "Cloud HSM" } final class GoogleCloudIDS: GoogleCloudPlatform, SubService { let name = "Google Cloud IDS" let dashboardName = "Cloud IDS" } final class GoogleCloudKeyManagementService: GoogleCloudPlatform, SubService { let name = "Google Cloud Key Management Service" let dashboardName = "Cloud Key Management Service" } final class GoogleCloudLoadBalancing: GoogleCloudPlatform, SubService { let name = "Google Cloud Load Balancing" let dashboardName = "Cloud Load Balancing" } final class GoogleCloudLogging: GoogleCloudPlatform, SubService { let name = "Google Cloud Logging" let dashboardName = "Cloud Logging" } final class GoogleCloudMemorystore: GoogleCloudPlatform, SubService { let name = "Google Cloud Memorystore" let dashboardName = "Cloud Memorystore" } final class GoogleCloudMonitoring: GoogleCloudPlatform, SubService { let name = "Google Cloud Monitoring" let dashboardName = "Cloud Monitoring" } final class GoogleCloudNAT: GoogleCloudPlatform, SubService { let name = "Google Cloud NAT" let dashboardName = "Cloud NAT" } final class GoogleCloudNaturalLanguageAPI: GoogleCloudPlatform, SubService { let name = "Google Cloud Natural Language API" let dashboardName = "Cloud Natural Language API" } final class GoogleCloudProfiler: GoogleCloudPlatform, SubService { let name = "Google Cloud Profiler" let dashboardName = "Cloud Profiler" } final class GoogleCloudRun: GoogleCloudPlatform, SubService { let name = "Google Cloud Run" let dashboardName = "Cloud Run" } final class GoogleCloudSecurityCommandCenter: GoogleCloudPlatform, SubService { let name = "Google Cloud Security Command Center" let dashboardName = "Cloud Security Command Center" } final class GoogleCloudShell: GoogleCloudPlatform, SubService { let name = "Google Cloud Shell" let dashboardName = "Cloud Shell" } final class GoogleCloudSourceRepositories: GoogleCloudPlatform, SubService { let name = "Google Cloud Source Repositories" let dashboardName = "Cloud Source Repositories" } final class GoogleCloudSpanner: GoogleCloudPlatform, SubService { let name = "Google Cloud Spanner" let dashboardName = "Cloud Spanner" } final class GoogleCloudStorageForFirebase: GoogleCloudPlatform, SubService { let name = "Google Cloud Storage for Firebase" let dashboardName = "Cloud Storage for Firebase" } final class GoogleCloudTalentSolutionJobSearch: GoogleCloudPlatform, SubService { let name = "Google Cloud Talent Solution - Job Search" let dashboardName = "Cloud Talent Solution - Job Search" } final class GoogleCloudTrace: GoogleCloudPlatform, SubService { let name = "Google Cloud Trace" let dashboardName = "Cloud Trace" } final class GoogleCloudTranslation: GoogleCloudPlatform, SubService { let name = "Google Cloud Translation" let dashboardName = "Cloud Translation" } final class GoogleCloudVision: GoogleCloudPlatform, SubService { let name = "Google Cloud Vision" let dashboardName = "Cloud Vision" } final class GoogleCloudWorkflows: GoogleCloudPlatform, SubService { let name = "Google Cloud Workflows" let dashboardName = "Cloud Workflows" } final class GoogleCloudWorkstations: GoogleCloudPlatform, SubService { let name = "Google Cloud Workstations" let dashboardName = "Cloud Workstations" } final class GoogleColabEnterprise: GoogleCloudPlatform, SubService { let name = "Google Colab Enterprise" let dashboardName = "Colab Enterprise" } final class GoogleContactCenterAIPlatform: GoogleCloudPlatform, SubService { let name = "Google Contact Center AI Platform" let dashboardName = "Contact Center AI Platform" } final class GoogleContactCenterInsights: GoogleCloudPlatform, SubService { let name = "Google Contact Center Insights" let dashboardName = "Contact Center Insights" } final class GoogleContainerRegistry: GoogleCloudPlatform, SubService { let name = "Google Container Registry" let dashboardName = "Container Registry" } final class GoogleDataCatalog: GoogleCloudPlatform, SubService { let name = "Google Data Catalog" let dashboardName = "Data Catalog" } final class GoogleDatabaseMigrationService: GoogleCloudPlatform, SubService { let name = "Google Database Migration Service" let dashboardName = "Database Migration Service" } final class GoogleDataform: GoogleCloudPlatform, SubService { let name = "Google Dataform" let dashboardName = "Dataform" } final class GoogleDataplex: GoogleCloudPlatform, SubService { let name = "Google Dataplex" let dashboardName = "Dataplex" } final class GoogleDataprocMetastore: GoogleCloudPlatform, SubService { let name = "Google Dataproc Metastore" let dashboardName = "Dataproc Metastore" } final class GoogleDatastream: GoogleCloudPlatform, SubService { let name = "Google Datastream" let dashboardName = "Datastream" } final class GoogleDeveloperConnect: GoogleCloudPlatform, SubService { let name = "Google Developer Connect" let dashboardName = "Developer Connect" } final class GoogleDialogflowCX: GoogleCloudPlatform, SubService { let name = "Google Dialogflow CX" let dashboardName = "Dialogflow CX" } final class GoogleDialogflowES: GoogleCloudPlatform, SubService { let name = "Google Dialogflow ES" let dashboardName = "Dialogflow ES" } final class GoogleDocumentAI: GoogleCloudPlatform, SubService { let name = "Google Document AI" let dashboardName = "Document AI" } final class GoogleEventarc: GoogleCloudPlatform, SubService { let name = "Google Eventarc" let dashboardName = "Eventarc" } final class GoogleGeminiCodeAssist: GoogleCloudPlatform, SubService { let name = "Google Gemini Code Assist" let dashboardName = "Gemini Code Assist" } final class GoogleGeminiEnterprise: GoogleCloudPlatform, SubService { let name = "Google Gemini Enterprise" let dashboardName = "Gemini Enterprise" } final class GoogleGKEFleetManagement: GoogleCloudPlatform, SubService { let name = "Google GKE fleet management" let dashboardName = "GKE fleet management" } final class GoogleAppEngine: GoogleCloudPlatform, SubService { let name = "Google App Engine" let dashboardName = "Google App Engine" } final class GoogleBigQuery: GoogleCloudPlatform, SubService { let name = "Google BigQuery" let dashboardName = "Google BigQuery" } final class GoogleCloudAndroidApp: GoogleCloudPlatform, SubService { let name = "Google Cloud Android App" let dashboardName = "Google Cloud Android App" } final class GoogleCloudBigtable: GoogleCloudPlatform, SubService { let name = "Google Cloud Bigtable" let dashboardName = "Google Cloud Bigtable" } final class GoogleCloudComposer: GoogleCloudPlatform, SubService { let name = "Google Cloud Composer" let dashboardName = "Google Cloud Composer" } final class GoogleCloudConsole: GoogleCloudPlatform, SubService { let name = "Google Cloud Console" let dashboardName = "Google Cloud Console" } final class GoogleCloudDataflow: GoogleCloudPlatform, SubService { let name = "Google Cloud Dataflow" let dashboardName = "Google Cloud Dataflow" } final class GoogleCloudDataproc: GoogleCloudPlatform, SubService { let name = "Google Cloud Dataproc" let dashboardName = "Google Cloud Dataproc" } final class GoogleCloudDatastore: GoogleCloudPlatform, SubService { let name = "Google Cloud Datastore" let dashboardName = "Google Cloud Datastore" } final class GoogleCloudDeploy: GoogleCloudPlatform, SubService { let name = "Google Cloud Deploy" let dashboardName = "Google Cloud Deploy" } final class GoogleCloudDNS: GoogleCloudPlatform, SubService { let name = "Google Cloud DNS" let dashboardName = "Google Cloud DNS" } final class GoogleCloudFunctions: GoogleCloudPlatform, SubService { let name = "Google Cloud Functions" let dashboardName = "Google Cloud Functions" } final class GoogleCloudIdentityAwareProxy: GoogleCloudPlatform, SubService { let name = "Google Cloud Identity-Aware Proxy" let dashboardName = "Google Cloud Identity-Aware Proxy" } final class GoogleCloudIOSApp: GoogleCloudPlatform, SubService { let name = "Google Cloud iOS App" let dashboardName = "Google Cloud iOS App" } final class GoogleCloudMarketplace: GoogleCloudPlatform, SubService { let name = "Google Cloud Marketplace" let dashboardName = "Google Cloud Marketplace" } final class GoogleCloudMigrationCenter: GoogleCloudPlatform, SubService { let name = "Google Cloud Migration Center" let dashboardName = "Google Cloud Migration Center" } final class GoogleCloudNetAppVolumes: GoogleCloudPlatform, SubService { let name = "Google Cloud NetApp Volumes" let dashboardName = "Google Cloud NetApp Volumes" } final class GoogleCloudPubSub: GoogleCloudPlatform, SubService { let name = "Google Cloud Pub/Sub" let dashboardName = "Google Cloud Pub/Sub" } final class GoogleCloudScheduler: GoogleCloudPlatform, SubService { let name = "Google Cloud Scheduler" let dashboardName = "Google Cloud Scheduler" } final class GoogleCloudSQL: GoogleCloudPlatform, SubService { let name = "Google Cloud SQL" let dashboardName = "Google Cloud SQL" } final class GoogleCloudStorage: GoogleCloudPlatform, SubService { let name = "Google Cloud Storage" let dashboardName = "Google Cloud Storage" } final class GoogleCloudSupport: GoogleCloudPlatform, SubService { let name = "Google Cloud Support" let dashboardName = "Google Cloud Support" } final class GoogleCloudTasks: GoogleCloudPlatform, SubService { let name = "Google Cloud Tasks" let dashboardName = "Google Cloud Tasks" } final class GoogleComputeEngine: GoogleCloudPlatform, SubService { let name = "Google Compute Engine" let dashboardName = "Google Compute Engine" } final class GoogleDistributedCloudEdge: GoogleCloudPlatform, SubService { let name = "Google Distributed Cloud Edge" let dashboardName = "Google Distributed Cloud Edge" } final class GoogleKubernetesEngine: GoogleCloudPlatform, SubService { let name = "Google Kubernetes Engine" let dashboardName = "Google Kubernetes Engine" } final class GoogleHealthcareAndLifeSciences: GoogleCloudPlatform, SubService { let name = "Google Healthcare and Life Sciences" let dashboardName = "Healthcare and Life Sciences" } final class GoogleHybridConnectivity: GoogleCloudPlatform, SubService { let name = "Google Hybrid Connectivity" let dashboardName = "Hybrid Connectivity" } final class GoogleIdentityAndAccessManagement: GoogleCloudPlatform, SubService { let name = "Google Identity and Access Management" let dashboardName = "Identity and Access Management" } final class GoogleIdentityPlatform: GoogleCloudPlatform, SubService { let name = "Google Identity Platform" let dashboardName = "Identity Platform" } final class GoogleInfrastructureManager: GoogleCloudPlatform, SubService { let name = "Google Infrastructure Manager" let dashboardName = "Infrastructure Manager" } final class GoogleIntegrationConnectors: GoogleCloudPlatform, SubService { let name = "Google Integration Connectors" let dashboardName = "Integration Connectors" } final class GoogleKeyAccessJustifications: GoogleCloudPlatform, SubService { let name = "Google Key Access Justifications" let dashboardName = "Key Access Justifications" } final class GoogleLookerGoogleCloudCore: GoogleCloudPlatform, SubService { let name = "Google Looker (Google Cloud core)" let dashboardName = "Looker (Google Cloud core)" } final class GoogleLookerStudio: GoogleCloudPlatform, SubService { let name = "Google Looker Studio" let dashboardName = "Looker Studio" } final class GoogleManagedLustre: GoogleCloudPlatform, SubService { let name = "Google Managed Lustre" let dashboardName = "Managed Lustre" } final class GoogleManagedServiceForApacheKafka: GoogleCloudPlatform, SubService { let name = "Google Managed Service for Apache Kafka" let dashboardName = "Managed Service for Apache Kafka" } final class GoogleManagedServiceForMicrosoftActiveDirectoryAD: GoogleCloudPlatform, SubService { let name = "Google Managed Service for Microsoft Active Directory (AD)" let dashboardName = "Managed Service for Microsoft Active Directory (AD)" } final class GoogleMediaCDN: GoogleCloudPlatform, SubService { let name = "Google Media CDN" let dashboardName = "Media CDN" } final class GoogleMemorystoreForMemcached: GoogleCloudPlatform, SubService { let name = "Google Memorystore for Memcached" let dashboardName = "Memorystore for Memcached" } final class GoogleMemorystoreForRedis: GoogleCloudPlatform, SubService { let name = "Google Memorystore for Redis" let dashboardName = "Memorystore for Redis" } final class GoogleMemorystoreForRedisCluster: GoogleCloudPlatform, SubService { let name = "Google Memorystore for Redis Cluster" let dashboardName = "Memorystore for Redis Cluster" } final class GoogleMemorystoreForValkey: GoogleCloudPlatform, SubService { let name = "Google Memorystore for Valkey" let dashboardName = "Memorystore for Valkey" } final class GoogleMigrateToVirtualMachines: GoogleCloudPlatform, SubService { let name = "Google Migrate to Virtual Machines" let dashboardName = "Migrate to Virtual Machines" } final class GoogleModelArmor: GoogleCloudPlatform, SubService { let name = "Google Model Armor" let dashboardName = "Model Armor" } final class GoogleNetworkConnectivityCenter: GoogleCloudPlatform, SubService { let name = "Google Network Connectivity Center" let dashboardName = "Network Connectivity Center" } final class GoogleNetworkIntelligenceCenter: GoogleCloudPlatform, SubService { let name = "Google Network Intelligence Center" let dashboardName = "Network Intelligence Center" } final class GoogleNetworkSecurityIntegration: GoogleCloudPlatform, SubService { let name = "Google Network Security Integration" let dashboardName = "Network Security Integration" } final class GoogleParallelstore: GoogleCloudPlatform, SubService { let name = "Google Parallelstore" let dashboardName = "Parallelstore" } final class GooglePersistentDisk: GoogleCloudPlatform, SubService { let name = "Google Persistent Disk" let dashboardName = "Persistent Disk" } final class GooglePersonalizedServiceHealth: GoogleCloudPlatform, SubService { let name = "Google Personalized Service Health" let dashboardName = "Personalized Service Health" } final class GooglePrivateServiceConnect: GoogleCloudPlatform, SubService { let name = "Google Private Service Connect" let dashboardName = "Private Service Connect" } final class GoogleProvisionedThroughput: GoogleCloudPlatform, SubService { let name = "Google Provisioned Throughput" let dashboardName = "Provisioned Throughput" } final class GooglePubSubLite: GoogleCloudPlatform, SubService { let name = "Google Pub/Sub Lite" let dashboardName = "Pub/Sub Lite" } final class GoogleReCAPTCHAEnterprise: GoogleCloudPlatform, SubService { let name = "Google reCAPTCHA Enterprise" let dashboardName = "reCAPTCHA Enterprise" } final class GoogleRecommendationAI: GoogleCloudPlatform, SubService { let name = "Google Recommendation AI" let dashboardName = "Recommendation AI" } final class GoogleRecommender: GoogleCloudPlatform, SubService { let name = "Google Recommender" let dashboardName = "Recommender" } final class GoogleResourceManagerAPI: GoogleCloudPlatform, SubService { let name = "Google Resource Manager API" let dashboardName = "Resource Manager API" } final class GoogleRetailAPI: GoogleCloudPlatform, SubService { let name = "Google Retail API" let dashboardName = "Retail API" } final class GoogleSecretManager: GoogleCloudPlatform, SubService { let name = "Google Secret Manager" let dashboardName = "Secret Manager" } final class GoogleSecureWebProxy: GoogleCloudPlatform, SubService { let name = "Google Secure Web Proxy" let dashboardName = "Secure Web Proxy" } final class GoogleServiceDirectory: GoogleCloudPlatform, SubService { let name = "Google Service Directory" let dashboardName = "Service Directory" } final class GoogleServiceExtensions: GoogleCloudPlatform, SubService { let name = "Google Service Extensions" let dashboardName = "Service Extensions" } final class GoogleSpectrumAccessSystem: GoogleCloudPlatform, SubService { let name = "Google Spectrum Access System" let dashboardName = "Spectrum Access System" } final class GoogleSpeechtoText: GoogleCloudPlatform, SubService { let name = "Google Speech-to-Text" let dashboardName = "Speech-to-Text" } final class GoogleStorageTransferService: GoogleCloudPlatform, SubService { let name = "Google Storage Transfer Service" let dashboardName = "Storage Transfer Service" } final class GoogleTexttoSpeech: GoogleCloudPlatform, SubService { let name = "Google Text-to-Speech" let dashboardName = "Text-to-Speech" } final class GoogleTrafficDirector: GoogleCloudPlatform, SubService { let name = "Google Traffic Director" let dashboardName = "Traffic Director" } final class GoogleTranscoderAPI: GoogleCloudPlatform, SubService { let name = "Google Transcoder API" let dashboardName = "Transcoder API" } final class GoogleUnifiedMaintenance: GoogleCloudPlatform, SubService { let name = "Google Unified Maintenance" let dashboardName = "Unified Maintenance" } final class GoogleVertexAIAutoMLImage: GoogleCloudPlatform, SubService { let name = "Google Vertex AI AutoML Image" let dashboardName = "Vertex AI AutoML Image" } final class GoogleVertexAIAutoMLTabular: GoogleCloudPlatform, SubService { let name = "Google Vertex AI AutoML Tabular" let dashboardName = "Vertex AI AutoML Tabular" } final class GoogleVertexAIAutoMLText: GoogleCloudPlatform, SubService { let name = "Google Vertex AI AutoML Text" let dashboardName = "Vertex AI AutoML Text" } final class GoogleVertexAIAutoMLVideo: GoogleCloudPlatform, SubService { let name = "Google Vertex AI AutoML Video" let dashboardName = "Vertex AI AutoML Video" } final class GoogleVertexAIBatchPrediction: GoogleCloudPlatform, SubService { let name = "Google Vertex AI Batch Prediction" let dashboardName = "Vertex AI Batch Prediction" } final class GoogleVertexAIDataLabeling: GoogleCloudPlatform, SubService { let name = "Google Vertex AI Data Labeling" let dashboardName = "Vertex AI Data Labeling" } final class GoogleVertexAIExplainableAI: GoogleCloudPlatform, SubService { let name = "Google Vertex AI Explainable AI" let dashboardName = "Vertex AI Explainable AI" } final class GoogleVertexAIFeatureStore: GoogleCloudPlatform, SubService { let name = "Google Vertex AI Feature Store" let dashboardName = "Vertex AI Feature Store" } final class GoogleVertexAIMatchingEngine: GoogleCloudPlatform, SubService { let name = "Google Vertex AI Matching Engine" let dashboardName = "Vertex AI Matching Engine" } final class GoogleVertexAIMLMetadata: GoogleCloudPlatform, SubService { let name = "Google Vertex AI ML Metadata" let dashboardName = "Vertex AI ML Metadata" } final class GoogleVertexAIModelMonitoring: GoogleCloudPlatform, SubService { let name = "Google Vertex AI Model Monitoring" let dashboardName = "Vertex AI Model Monitoring" } final class GoogleVertexAIModelRegistry: GoogleCloudPlatform, SubService { let name = "Google Vertex AI Model Registry" let dashboardName = "Vertex AI Model Registry" } final class GoogleVertexAIOnlinePrediction: GoogleCloudPlatform, SubService { let name = "Google Vertex AI Online Prediction" let dashboardName = "Vertex AI Online Prediction" } final class GoogleVertexAIPipelines: GoogleCloudPlatform, SubService { let name = "Google Vertex AI Pipelines" let dashboardName = "Vertex AI Pipelines" } final class GoogleVertexAISearch: GoogleCloudPlatform, SubService { let name = "Google Vertex AI Search" let dashboardName = "Vertex AI Search" } final class GoogleVertexAITensorBoard: GoogleCloudPlatform, SubService { let name = "Google Vertex AI TensorBoard" let dashboardName = "Vertex AI TensorBoard" } final class GoogleVertexAITraining: GoogleCloudPlatform, SubService { let name = "Google Vertex AI Training" let dashboardName = "Vertex AI Training" } final class GoogleVertexAIVizier: GoogleCloudPlatform, SubService { let name = "Google Vertex AI Vizier" let dashboardName = "Vertex AI Vizier" } final class GoogleVertexAIWorkbenchUserManagedNotebooks: GoogleCloudPlatform, SubService { let name = "Google Vertex AI Workbench User Managed Notebooks" let dashboardName = "Vertex AI Workbench User Managed Notebooks" } final class GoogleVertexGeminiAPI: GoogleCloudPlatform, SubService { let name = "Google Vertex Gemini API" let dashboardName = "Vertex Gemini API" } final class GoogleVertexImagenAPI: GoogleCloudPlatform, SubService { let name = "Google Vertex Imagen API" let dashboardName = "Vertex Imagen API" } final class GoogleVertexVeoAPI: GoogleCloudPlatform, SubService { let name = "Google Vertex Veo API" let dashboardName = "Vertex Veo API" } final class GoogleVideoIntelligenceAPI: GoogleCloudPlatform, SubService { let name = "Google Video Intelligence API" let dashboardName = "Video Intelligence API" } final class GoogleVirtualPrivateCloudVPC: GoogleCloudPlatform, SubService { let name = "Google Virtual Private Cloud (VPC)" let dashboardName = "Virtual Private Cloud (VPC)" } final class GoogleVMWareEngine: GoogleCloudPlatform, SubService { let name = "Google VMWare engine" let dashboardName = "VMWare engine" } final class GoogleVPCServiceControls: GoogleCloudPlatform, SubService { let name = "Google VPC Service Controls" let dashboardName = "VPC Service Controls" } final class GoogleWebRisk: GoogleCloudPlatform, SubService { let name = "Google Web Risk" let dashboardName = "Web Risk" } ================================================ FILE: stts/Services/Generated/SalesforceProducts.swift ================================================ // This file is generated by generate_salesforce_services.swift and should not be modified manually. // swiftlint:disable superfluous_disable_command type_name import Foundation final class SalesforceB2CCommerceCloudAll: SalesforceB2CCommerceCloud, ServiceCategory { let categoryName = "Salesforce B2C Commerce Cloud" let subServiceSuperclass: AnyObject.Type = BaseSalesforceB2CCommerceCloud.self let name = "Salesforce B2C Commerce Cloud (All Regions)" let key = "B2C_Commerce_Cloud" let location = "*" } final class SalesforceB2CCommerceCloudAPAC: SalesforceB2CCommerceCloud, SubService { let name = "Salesforce B2C Commerce Cloud (APAC)" let key = "B2C_Commerce_Cloud" let location = "APAC" } final class SalesforceB2CCommerceCloudEMEA: SalesforceB2CCommerceCloud, SubService { let name = "Salesforce B2C Commerce Cloud (EMEA)" let key = "B2C_Commerce_Cloud" let location = "EMEA" } final class SalesforceB2CCommerceCloudNA: SalesforceB2CCommerceCloud, SubService { let name = "Salesforce B2C Commerce Cloud (NA)" let key = "B2C_Commerce_Cloud" let location = "NA" } final class SalesforceExperienceCloudAll: SalesforceExperienceCloud, ServiceCategory { let categoryName = "Salesforce Experience Cloud" let subServiceSuperclass: AnyObject.Type = BaseSalesforceExperienceCloud.self let name = "Salesforce Experience Cloud (All Regions)" let key = "Community_Cloud" let location = "*" } final class SalesforceExperienceCloudAPAC: SalesforceExperienceCloud, SubService { let name = "Salesforce Experience Cloud (APAC)" let key = "Community_Cloud" let location = "APAC" } final class SalesforceExperienceCloudEMEA: SalesforceExperienceCloud, SubService { let name = "Salesforce Experience Cloud (EMEA)" let key = "Community_Cloud" let location = "EMEA" } final class SalesforceExperienceCloudNA: SalesforceExperienceCloud, SubService { let name = "Salesforce Experience Cloud (NA)" let key = "Community_Cloud" let location = "NA" } final class DatoramaAll: Datorama, ServiceCategory { let categoryName = "Datorama" let subServiceSuperclass: AnyObject.Type = BaseDatorama.self let name = "Datorama (All Regions)" let key = "Datorama" let location = "*" } final class DatoramaEMEA: Datorama, SubService { let name = "Datorama (EMEA)" let key = "Datorama" let location = "EMEA" } final class DatoramaNA: Datorama, SubService { let name = "Datorama (NA)" let key = "Datorama" let location = "NA" } final class HerokuAll: Heroku, ServiceCategory { let categoryName = "Heroku" let subServiceSuperclass: AnyObject.Type = BaseHeroku.self let name = "Heroku (All Regions)" let key = "Heroku" let location = "*" } final class HerokuAPAC: Heroku, SubService { let name = "Heroku (APAC)" let key = "Heroku" let location = "APAC" } final class HerokuEMEA: Heroku, SubService { let name = "Heroku (EMEA)" let key = "Heroku" let location = "EMEA" } final class HerokuNA: Heroku, SubService { let name = "Heroku (NA)" let key = "Heroku" let location = "NA" } final class MCAccountEngagementAll: MCAccountEngagement, ServiceCategory { let categoryName = "MCAccountEngagement" let subServiceSuperclass: AnyObject.Type = BaseMCAccountEngagement.self let name = "MCAccountEngagement (All Regions)" let key = "MCAccountEngagement" let location = "*" } final class MCAccountEngagementNA: MCAccountEngagement, SubService { let name = "MCAccountEngagement (NA)" let key = "MCAccountEngagement" let location = "NA" } final class MCPersonalizationAll: MCPersonalization, ServiceCategory { let categoryName = "MCPersonalization" let subServiceSuperclass: AnyObject.Type = BaseMCPersonalization.self let name = "MCPersonalization (All Regions)" let key = "MCPersonalization" let location = "*" } final class MCPersonalizationAPAC: MCPersonalization, SubService { let name = "MCPersonalization (APAC)" let key = "MCPersonalization" let location = "APAC" } final class MCPersonalizationEMEA: MCPersonalization, SubService { let name = "MCPersonalization (EMEA)" let key = "MCPersonalization" let location = "EMEA" } final class MCPersonalizationNA: MCPersonalization, SubService { let name = "MCPersonalization (NA)" let key = "MCPersonalization" let location = "NA" } final class SalesforceMarketingCloudAll: SalesforceMarketingCloud, ServiceCategory { let categoryName = "Salesforce Marketing Cloud" let subServiceSuperclass: AnyObject.Type = BaseSalesforceMarketingCloud.self let name = "Salesforce Marketing Cloud (All Regions)" let key = "Marketing_Cloud" let location = "*" } final class SalesforceMarketingCloudAPAC: SalesforceMarketingCloud, SubService { let name = "Salesforce Marketing Cloud (APAC)" let key = "Marketing_Cloud" let location = "APAC" } final class SalesforceMarketingCloudEMEA: SalesforceMarketingCloud, SubService { let name = "Salesforce Marketing Cloud (EMEA)" let key = "Marketing_Cloud" let location = "EMEA" } final class SalesforceMarketingCloudNA: SalesforceMarketingCloud, SubService { let name = "Salesforce Marketing Cloud (NA)" let key = "Marketing_Cloud" let location = "NA" } final class MulesoftAll: Mulesoft, ServiceCategory { let categoryName = "Mulesoft" let subServiceSuperclass: AnyObject.Type = BaseMulesoft.self let name = "Mulesoft (All Regions)" let key = "Mulesoft" let location = "*" } final class MulesoftAPAC: Mulesoft, SubService { let name = "Mulesoft (APAC)" let key = "Mulesoft" let location = "APAC" } final class MulesoftEMEA: Mulesoft, SubService { let name = "Mulesoft (EMEA)" let key = "Mulesoft" let location = "EMEA" } final class MulesoftNA: Mulesoft, SubService { let name = "Mulesoft (NA)" let key = "Mulesoft" let location = "NA" } final class SalesforceServicesAll: SalesforceServices, ServiceCategory { let categoryName = "Salesforce Services" let subServiceSuperclass: AnyObject.Type = BaseSalesforceServices.self let name = "Salesforce Services (All Regions)" let key = "Salesforce_Services" let location = "*" } final class SalesforceServicesAPAC: SalesforceServices, SubService { let name = "Salesforce Services (APAC)" let key = "Salesforce_Services" let location = "APAC" } final class SalesforceServicesEMEA: SalesforceServices, SubService { let name = "Salesforce Services (EMEA)" let key = "Salesforce_Services" let location = "EMEA" } final class SalesforceServicesNA: SalesforceServices, SubService { let name = "Salesforce Services (NA)" let key = "Salesforce_Services" let location = "NA" } final class SpiffAll: Spiff, ServiceCategory { let categoryName = "Spiff" let subServiceSuperclass: AnyObject.Type = BaseSpiff.self let name = "Spiff (All Regions)" let key = "Spiff" let location = "*" } final class SpiffEMEA: Spiff, SubService { let name = "Spiff (EMEA)" let key = "Spiff" let location = "EMEA" } final class SpiffNA: Spiff, SubService { let name = "Spiff (NA)" let key = "Spiff" let location = "NA" } final class TableauAll: Tableau, ServiceCategory { let categoryName = "Tableau" let subServiceSuperclass: AnyObject.Type = BaseTableau.self let name = "Tableau (All Regions)" let key = "Tableau" let location = "*" } final class TableauAPAC: Tableau, SubService { let name = "Tableau (APAC)" let key = "Tableau" let location = "APAC" } final class TableauEMEA: Tableau, SubService { let name = "Tableau (EMEA)" let key = "Tableau" let location = "EMEA" } final class TableauNA: Tableau, SubService { let name = "Tableau (NA)" let key = "Tableau" let location = "NA" } ================================================ FILE: stts/Services/GoogleCloudPlatformAll.swift ================================================ // // GoogleCloudPlatformAll.swift // stts // import Foundation class GoogleCloudPlatformAll: GoogleCloudPlatform, ServiceCategory { let categoryName = "Google Cloud Platform" let subServiceSuperclass: AnyObject.Type = BaseGoogleCloudPlatform.self let name = "Google Cloud Platform (All)" } ================================================ FILE: stts/Services/MiroAll.swift ================================================ // // MiroAll.swift // stts import Foundation import Kanna class MiroAll: IndependentService, ServiceCategory { let categoryName: String = "Miro" let subServiceSuperclass: any AnyObject.Type = MiroService.self let name = "Miro (All Regions)" let url = URL(string: "https://status.miro.com/")! private func serviceStatus(fromIconSuffix suffix: String) -> ServiceStatus { switch suffix { case "operational": return .good case "degraded-performance", "partial-outage": return .minor case "full-outage": return .major case "under-maintenance": return .maintenance default: return .undetermined } } private func iconSuffix(fromClassName className: String) -> String? { guard let range = className.range(of: "text-icon-") else { return nil } return String(className[range.upperBound...]).components(separatedBy: " ").first } override func updateStatus() async throws { let doc = try await html(from: url) var regions: [(name: String, status: ServiceStatus)] = [] for item in doc.css("[data-testid='subpage-item']") { guard let href = item["href"] else { continue } let regionName = String(href.dropFirst()).uppercased() let svgClass = item.css("svg").first?.className ?? "" guard let suffix = iconSuffix(fromClassName: svgClass) else { continue } regions.append((name: regionName, status: serviceStatus(fromIconSuffix: suffix))) } guard !regions.isEmpty else { throw StatusUpdateError.parseError(nil) } let worstStatus = regions.map(\.status).max() ?? .undetermined guard worstStatus != .good else { statusDescription = ServiceStatusDescription(status: .good, message: "We\u{2019}re fully operational") return } let message = regions .filter { $0.status != .good } .map { "\($0.name): We\u{2019}re currently experiencing issues" } .joined(separator: "\n") statusDescription = ServiceStatusDescription(status: worstStatus, message: message) } } ================================================ FILE: stts/Services/Okta.swift ================================================ // // Okta.swift // stts // import Foundation import Kanna class Okta: IndependentService { private struct Incident: Decodable { let status: String let category: String let serviceFeature: String? enum CodingKeys: String, CodingKey { case status = "Status__c" case category = "Category__c" case serviceFeature = "Service_Feature__c" } } private enum Category: String { case serviceDisruption = "Service Disruption" case majorServiceDisruption = "Major Service Disruption" case minorServiceDisruption = "Minor Service Disruption" case serviceDegradation = "Service Degradation" case performanceIssue = "Performance Issue" case featureDisruption = "Feature Disruption" var serviceStatus: ServiceStatus { switch self { case .serviceDisruption, .majorServiceDisruption, .minorServiceDisruption: return .major case .serviceDegradation, .performanceIssue, .featureDisruption: return .minor } } } let url = URL(string: "https://status.okta.com")! override func updateStatus() async throws { let doc = try await html(from: url) guard let incidentsSpan = doc.css("[data-id='incidents']").first, let jsonText = incidentsSpan.text, let jsonData = jsonText.data(using: .utf8) else { throw StatusUpdateError.parseError(nil) } let incidents: [Incident] do { incidents = try JSONDecoder().decode([Incident].self, from: jsonData) } catch { throw StatusUpdateError.decodingError(error) } let openIncidents = incidents.filter { $0.status != "Resolved" } if openIncidents.isEmpty { statusDescription = ServiceStatusDescription(status: .good, message: "System Operational") return } let worstStatus = openIncidents.compactMap { incident -> ServiceStatus? in if incident.serviceFeature == "tp" { return .minor } return Category(rawValue: incident.category)?.serviceStatus }.max() ?? .undetermined let categories = Set(openIncidents.map { $0.category }) let message = categories.sorted().joined(separator: ", ") statusDescription = ServiceStatusDescription(status: worstStatus, message: message) } } ================================================ FILE: stts/Services/OracleNetSuite.swift ================================================ // // OracleNetSuite.swift // stts // import Foundation private struct NetSuiteResponse: Codable { struct NetSuiteStatus: Codable { enum Indicator: String, Codable { case none case minor case major case critical case maintenance var serviceStatus: ServiceStatus { switch self { case .none: return .good case .minor: return .minor case .major, .critical: return .major case .maintenance: return .maintenance } } } let indicator: Indicator let description: String } let status: NetSuiteStatus } class OracleNetSuite: IndependentService { let name = "Oracle NetSuite" let url = URL(string: "https://status.netsuite.com")! override func updateStatus() async throws { let response = try await decoded(NetSuiteResponse.self, from: url.appendingPathComponent("api/v2/status.json")) statusDescription = ServiceStatusDescription( status: response.status.indicator.serviceStatus, message: response.status.description ) } } ================================================ FILE: stts/Services/PagerDuty/PagerDuty.swift ================================================ // // PagerDuty.swift // stts // import Foundation final class PagerDuty: PagerDutyService { let url = URL(string: "https://status.pagerduty.com")! } ================================================ FILE: stts/Services/PayPal/PayPalAPIProduction.swift ================================================ // // PayPalAPIProduction.swift // stts // import Foundation final class PayPalAPIProduction: PayPal { let name = "PayPal API" let component = PayPalComponent.api(.production) } ================================================ FILE: stts/Services/PayPal/PayPalAPISandbox.swift ================================================ // // PayPalAPISandbox.swift // stts // import Foundation final class PayPalAPISandbox: PayPal { let name = "PayPal API (Sandbox)" let component = PayPalComponent.api(.sandbox) } ================================================ FILE: stts/Services/PayPal/PayPalProductProduction.swift ================================================ // // PayPalProductProduction.swift // stts // import Foundation final class PayPalProductProduction: PayPal { let name = "PayPal Product" let component = PayPalComponent.product(.production) } ================================================ FILE: stts/Services/PayPal/PayPalProductSandbox.swift ================================================ // // PayPalProductSandbox.swift // stts // import Foundation final class PayPalProductSandbox: PayPal { let name = "PayPal Product (Sandbox)" let component = PayPalComponent.product(.sandbox) } ================================================ FILE: stts/Services/PlayStation Network/PSNAmerica.swift ================================================ // // PSNAmerica.swift // stts // import Foundation final class PSNAmerica: PlayStationNetwork { let region: PlayStationNetworkRegion = .scea let name = "PlayStation Network (America)" } ================================================ FILE: stts/Services/PlayStation Network/PSNAsia.swift ================================================ // // PSNAsia.swift // stts // import Foundation final class PSNAsia: PlayStationNetwork { let region: PlayStationNetworkRegion = .sceja let name = "PlayStation Network (Asia)" } ================================================ FILE: stts/Services/PlayStation Network/PSNEurope.swift ================================================ // // PSNEurope.swift // stts // import Foundation final class PSNEurope: PlayStationNetwork { let region: PlayStationNetworkRegion = .scee let name = "PlayStation Network (Europe)" } ================================================ FILE: stts/Services/SendbirdAll.swift ================================================ // // SendbirdAll.swift // SendbirdAll // import Foundation class SendbirdAll: IndependentService, ServiceCategory { static var sendbirdServices: [SendbirdService] = [] let categoryName = "Sendbird" let subServiceSuperclass: AnyObject.Type = SendbirdService.self let name = "Sendbird (All)" let url = URL(string: "https://sendbird.com/status")! override func updateStatus() async throws { await withThrowingTaskGroup(of: Void.self) { group in for service in Self.sendbirdServices { group.addTask { try await service.updateStatus() } } } statusDescription = statusDescriptionFromServices() } private func statusDescriptionFromServices() -> ServiceStatusDescription { var messageComponents: [String] = [] for service in Self.sendbirdServices { if service.status != .good { messageComponents.append(service.name) messageComponents.append("* \(service.message)") } } let worstStatus = Self.sendbirdServices.map { $0.status }.max() ?? .undetermined var message = messageComponents.joined(separator: "\n") if message.isEmpty { switch worstStatus { case .undetermined: message = "Unexpected response" case .good: message = "Operational" case .minor: message = "Minor outage" case .major: message = "Major outage" case .notice: message = "Degraded service" case .maintenance: message = "Maintenance" } } return ServiceStatusDescription(status: worstStatus, message: message) } } ================================================ FILE: stts/Services/SignalWire.swift ================================================ // // SignalWire.swift // stts // import Foundation class SignalWire: IndependentService { let url = URL(string: "https://status.signalwire.com")! override func updateStatus() async throws { let componentsURL = URL(string: "https://status.signalwire.com/api/components")! let components = try await decoded([Component].self, from: componentsURL) let affectedComponents = components.filter { $0.status.status != .good } let status: ServiceStatus let message: String if affectedComponents.isEmpty { status = .good message = "Operational" } else { status = affectedComponents.map { $0.status.status }.max() ?? .undetermined message = affectedComponents.map { "* \($0.name): \($0.status.rawValue)" }.joined(separator: "\n") } statusDescription = ServiceStatusDescription(status: status, message: message) } } private struct Component: Codable { enum ComponentStatus: String, Codable { case operational = "Operational" case underMaintenance = "Under Maintenance" case degradedPerformance = "Degraded Performance" case partialOutage = "Partial Outage" case majorOutage = "Major Outage" var status: ServiceStatus { switch self { case .operational: return .good case .underMaintenance: return .maintenance case .degradedPerformance, .partialOutage: return .minor case .majorOutage: return .major } } } let name: String let status: ComponentStatus } ================================================ FILE: stts/Services/Slack.swift ================================================ // // Slack.swift // stts // import Foundation import Kanna class Slack: IndependentService { private enum SlackStatus: String { case check = "tablecheck.png" case outage = "tableoutage.png" case incident = "tableincident.png" case maintenance = "tablemaintenance.png" case notice = "tablenotice.png" var serviceStatus: ServiceStatus { switch self { case .check: return .good case .outage: return .major case .incident: return .minor case .maintenance: return .maintenance case .notice: return .notice } } } let url = URL(string: "https://status.slack.com")! override func updateStatus() async throws { let doc = try await html(from: url) let serviceImages = doc.css("#services .service.header img") guard serviceImages.count > 0 else { throw StatusUpdateError.decodingError(nil) } let imageURLs = serviceImages.compactMap { $0["src"] } let statuses = imageURLs.compactMap { SlackStatus(rawValue: ($0.lowercased() as NSString).lastPathComponent) } let status = statuses.map { $0.serviceStatus }.max() ?? .undetermined let message = doc.css("#current_status h1").first?.text ?? "Unexpected response" statusDescription = ServiceStatusDescription(status: status, message: message) } } ================================================ FILE: stts/Services/Stripe.swift ================================================ // // Stripe.swift // stts // import Foundation private struct StripeCurrentStatus: Codable { enum Status: String, Codable { case up case degraded case down // Not sure what pending & paused are (maybe temporary states until all data is loaded?), but // we'll add them to the enum just in case, and we'll treat them as maintenance like the old version. case pending case paused var serviceStatus: ServiceStatus { switch self { case .up: return .good case .degraded: return .minor case .pending, .paused: return .maintenance case .down: return .major } } } enum CodingKeys: String, CodingKey { case message case uptimeStatus = "UptimeStatus" } let message: String let uptimeStatus: Status } class Stripe: IndependentService { let url = URL(string: "https://status.stripe.com")! override func updateStatus() async throws { let currentStatus = try await decoded( StripeCurrentStatus.self, from: url.appendingPathComponent("current/full") ) statusDescription = ServiceStatusDescription( status: currentStatus.uptimeStatus.serviceStatus, message: currentStatus.message ) } } ================================================ FILE: stts/Services/Super/AWSService.swift ================================================ // // AWSService.swift // stts // import Foundation typealias AWSAllService = BaseAWSAllService & RequiredServiceProperties & RequiredAWSAllServiceProperties typealias AWSRegionService = BaseAWSRegionService & RequiredServiceProperties & RequiredAWSRegionServiceProperties typealias AWSNamedService = BaseAWSNamedService & RequiredServiceProperties & RequiredAWSNamedServiceProperties protocol RequiredAWSAllServiceProperties {} protocol RequiredAWSNamedServiceProperties { var name: String { get } var ids: Set { get } } protocol RequiredAWSRegionServiceProperties { var name: String { get } var id: String { get } } class BaseAWSAllService: BaseAWSService {} class BaseAWSRegionService: BaseAWSService {} class BaseAWSNamedService: BaseAWSService {} class BaseAWSService: BaseIndependentService { private static var store = AWSStore(url: URL(string: "https://health.aws.amazon.com/public/currentevents")!) let url = URL(string: "https://health.aws.amazon.com/health/status")! override func updateStatus() async throws { if let allService = self as? AWSAllService { statusDescription = try await BaseAWSService.store.updatedStatus(for: allService) } else if let namedService = self as? AWSNamedService { statusDescription = try await BaseAWSService.store.updatedStatus(for: namedService) } else if let regionService = self as? AWSRegionService { statusDescription = try await BaseAWSService.store.updatedStatus(for: regionService) } else { fatalError("BaseAWSService should not be used directly.") } } } ================================================ FILE: stts/Services/Super/AWSStore.swift ================================================ // // AWSStore.swift // stts // import Foundation // When all is good, the response from currentevents is empty; luckily I found this incident on web.archive.org: // [{ // "date": "1678726651", // "region_name": "Oregon", // "status": "0", // "service": "internetconnectivity-us-west-2", // "service_name": "AWS Internet Connectivity", // "summary": "[RESOLVED] Internet Connectivity in the US-WEST-2 Region", // "event_log": [{ // "summary": "[RESOLVED] Internet Connectivity in the US-WEST-2 Region", // "message": "Between 8:25 AM and 9:16 AM PDT, we experienced elevated packet loss and latency to a small set of internet destinations in the US-WEST-2 Region. Connectivity within the US-WEST-2 Region was not impacted. The issue has been resolved and the services are operating normally.", // "status": 1, // "timestamp": 1678726620 // }], // "impacted_services": { // "elb-us-west-2": { // "service_name": "Amazon Elastic Load Balancing", // "current": "0", // "max": "1" // }, // "natgateway-us-west-2": { // "service_name": "AWS NAT Gateway", // "current": "0", // "max": "1" // }, // "ec2-us-west-2": { // "service_name": "Amazon Elastic Compute Cloud", // "current": "0", // "max": "1" // } // }, // "end_time": "1678727476" // }] struct AWSIncident: Codable { enum CodingKeys: String, CodingKey { case regionName = "region_name" case status case serviceID = "service" case serviceName = "service_name" case impactedServices = "impacted_services" } let regionName: String let status: String let serviceID: String let serviceName: String let impactedServices: [String: ImpactedService] func impactedServices(for service: AWSNamedService) -> Set { var result = Set() if service.ids.contains(serviceID) { result.insert(serviceID) } return result.union(service.ids.intersection(Set(impactedServices.keys))) } struct ImpactedService: Codable { let name: String private enum CodingKeys: String, CodingKey { case name = "service_name" } } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) regionName = try container.decode(String.self, forKey: .regionName) if let statusString = try? container.decode(String.self, forKey: .status) { status = statusString } else { status = String(try container.decode(Int.self, forKey: .status)) } serviceID = try container.decode(String.self, forKey: .serviceID) serviceName = try container.decode(String.self, forKey: .serviceName) impactedServices = try container.decode([String: ImpactedService].self, forKey: .impactedServices) } } class AWSStore: ServiceStore<[AWSIncident]> { private var url: URL init(url: URL) { self.url = url } override func retrieveUpdatedState() async throws -> [AWSIncident] { return try await decoded([AWSIncident].self, from: url) } func updatedStatus(for aws: AWSAllService) async throws -> ServiceStatusDescription { let updatedState = try await updatedState() var status: ServiceStatus = .good var impactedServiceNames = Set() for incident in updatedState { guard incident.status != "0" else { continue } status = .minor impactedServiceNames.insert(incident.serviceName) for (_, impactedService) in incident.impactedServices { impactedServiceNames.insert(impactedService.name) } } return ServiceStatusDescription( status: status, message: message(for: status, impactedServiceNames: impactedServiceNames) ) } func updatedStatus(for region: AWSRegionService) async throws -> ServiceStatusDescription { let updatedState = try await updatedState() var status: ServiceStatus = .good var impactedServiceNames = Set() for incident in updatedState { guard incident.status != "0" else { continue } if incident.regionName == region.name { status = .minor impactedServiceNames.insert(incident.serviceName) for (_, impactedService) in incident.impactedServices { impactedServiceNames.insert(impactedService.name) } } } return ServiceStatusDescription( status: status, message: message(for: status, impactedServiceNames: impactedServiceNames) ) } func updatedStatus(for namedService: AWSNamedService) async throws -> ServiceStatusDescription { let updatedState = try await updatedState() var status: ServiceStatus = .good for incident in updatedState { guard incident.status != "0" else { continue } let impactedServiceIDs = incident.impactedServices(for: namedService) if !impactedServiceIDs.isEmpty { status = .minor break } } return ServiceStatusDescription( status: status, message: message(for: status, impactedServiceNames: nil) ) } private func message(for status: ServiceStatus, impactedServiceNames: Set?) -> String { let serviceNames = impactedServiceNames ?? [] let message: String if serviceNames.isEmpty { switch status { case .good: message = "No recent issues" default: message = "Impacted" } } else { message = "Impacted services:\n" + serviceNames.joined(separator: "\n") } return message } } ================================================ FILE: stts/Services/Super/Adobe.swift ================================================ // // Adobe.swift // stts // import Foundation typealias AdobeCreativeCloud = BaseAdobeCreativeCloud & RequiredServiceProperties & AdobeStoreService class BaseAdobeCreativeCloud: BaseAdobe {} class BaseAdobeDocumentCloud: BaseAdobe {} typealias AdobeDocumentCloud = BaseAdobeDocumentCloud & RequiredServiceProperties & AdobeStoreService typealias AdobeExperienceCloud = BaseAdobeExperienceCloud & RequiredServiceProperties & AdobeStoreService class BaseAdobeExperienceCloud: BaseAdobe {} typealias AdobeExperiencePlatform = BaseAdobeExperiencePlatform & RequiredServiceProperties & AdobeStoreService class BaseAdobeExperiencePlatform: BaseAdobe {} typealias AdobeServices = BaseAdobeServices & RequiredServiceProperties & AdobeStoreService class BaseAdobeServices: BaseAdobe {} typealias Adobe = BaseAdobe & RequiredServiceProperties & AdobeStoreService class BaseAdobe: BaseIndependentService { static var store = AdobeStore() let url = URL(string: "https://status.adobe.com")! override func updateStatus() async throws { guard let realSelf = self as? Adobe else { fatalError("BaseAdobe should not be used directly.") } statusDescription = try await BaseAdobe.store.updatedStatus(for: realSelf) } } ================================================ FILE: stts/Services/Super/AdobeStore.swift ================================================ // // AdobeStore.swift // stts // import Foundation protocol AdobeStoreService { var id: String { get } } private enum Status: String { case opened case started case updated case reopened case discovery case scheduled case closed case canceled case completed case dismissed var isOpen: Bool { switch self { case .opened, .started, .updated, .reopened, .discovery, .scheduled: return true case .closed, .canceled, .completed, .dismissed: return false } } init?(_ string: String) { self.init(rawValue: string.lowercased()) } } private enum Severity: String { case major case minor case potential case maintenance case trivial var status: ServiceStatus { switch self { case .major: return .major case .minor: return .minor case .maintenance: return .maintenance case .potential, .trivial: return .notice } } init?(_ string: String) { self.init(rawValue: string.lowercased()) } } private struct StatusEvents { struct Cloud { let id: String let name: String static func clouds(from dictionary: [String: Any]) -> [Self] { dictionary.compactMap { _, object in guard let dict = object as? [String: Any] else { return nil } return Self(dict) } } init?(_ dict: [String: Any]) { guard let id = dict["id"] as? String, let name = dict["name"] as? String else { return nil } self.id = id self.name = name } } struct MaintenanceProduct { let id: String let name: String static func products(from dictionary: [String: Any]) -> [Self] { dictionary.compactMap { _, object in guard let dict = object as? [String: Any] else { return nil } return Self(dict) } } init?(_ dict: [String: Any]) { guard let id = dict["id"] as? String, let name = dict["name"] as? String else { return nil } self.id = id self.name = name } } struct IncidentProduct { let id: String let name: String let history: [IncidentHistoryItem] static func products(from dictionary: [String: Any]) -> [Self] { dictionary.compactMap { _, object in guard let dict = object as? [String: Any] else { return nil } return Self(dict) } } init?(_ dict: [String: Any]) { guard let id = dict["id"] as? String, let name = dict["name"] as? String, let historyDictionary = dict["history"] as? [String: Any] else { return nil } self.id = id self.name = name self.history = IncidentHistoryItem.historyItems(from: historyDictionary) } } struct IncidentHistoryItem { let id: String let status: Status let severity: Severity static func historyItems(from dictionary: [String: Any]) -> [Self] { // We want them to be sorted by date and in this case the keys are timestamps let sortedKeys = dictionary.keys.sorted() return sortedKeys.compactMap { (key: String) -> Self? in guard let dict = dictionary[key] as? [String: Any] else { return nil } return Self(dict) } } init?(_ dict: [String: Any]) { guard let id = dict["id"] as? String, let status = Status(dict["status"] as? String ?? ""), let severity = Severity(dict["severity"] as? String ?? "") else { return nil } self.id = id self.status = status self.severity = severity } } struct MaintenanceEvent { let id: String let status: Status let clouds: [Cloud] let products: [MaintenanceProduct] static func events(from dictionary: [String: Any]) -> [Self] { dictionary.compactMap { _, object in guard let dict = object as? [String: Any] else { return nil } return Self(dict) } } init?(_ dict: [String: Any]) { guard let id = dict["id"] as? String, let status = Status(dict["status"] as? String ?? ""), let cloudsDictionary = dict["clouds"] as? [String: Any], let productsDictionary = dict["products"] as? [String: Any] else { return nil } self.id = id self.status = status self.clouds = Cloud.clouds(from: cloudsDictionary) self.products = MaintenanceProduct.products(from: productsDictionary) } } struct IncidentEvent { let id: String let clouds: [Cloud] let products: [IncidentProduct] static func events(from dictionary: [String: Any]) -> [Self] { dictionary.compactMap { _, object in guard let dict = object as? [String: Any] else { return nil } return Self(dict) } } init?(_ dict: [String: Any]) { guard let id = dict["id"] as? String, let cloudsDictionary = dict["clouds"] as? [String: Any], let productsDictionary = dict["products"] as? [String: Any] else { return nil } self.id = id self.clouds = Cloud.clouds(from: cloudsDictionary) self.products = IncidentProduct.products(from: productsDictionary) } } let maintenanceEvents: [MaintenanceEvent] let incidentEvents: [IncidentEvent] init?(_ data: Data) { guard let structure = try? JSONSerialization.jsonObject(with: data) as? [String: Any], let maintenanceEventDictionary = structure["maintenanceEvent"] as? [String: Any], let maintenanceDictionary = maintenanceEventDictionary["maintenance"] as? [String: Any], let incidentEventDictionary = structure["incidentEvent"] as? [String: Any], let incidentsDictionary = incidentEventDictionary["incidents"] as? [String: Any] else { return nil } maintenanceEvents = MaintenanceEvent.events(from: maintenanceDictionary) incidentEvents = IncidentEvent.events(from: incidentsDictionary) } } class AdobeStore: ServiceStore<[String: ServiceStatus]> { let url = URL(string: "https://data.status.adobe.com/adobestatus/StatusEvents")! override func retrieveUpdatedState() async throws -> [String: ServiceStatus] { let data = try await rawData(from: url) guard let statusEvents = StatusEvents(data) else { throw StatusUpdateError.decodingError(nil) } var statuses: [String: ServiceStatus] = [:] statusEvents.maintenanceEvents.forEach { maintenanceEvent in if maintenanceEvent.status == .started { let affectedIDs = maintenanceEvent.clouds.map { $0.id } + maintenanceEvent.products.map { $0.id } affectedIDs.forEach { statuses[$0] = .maintenance } } } statusEvents.incidentEvents.forEach { incidentEvent in let affectedCloudIDs = incidentEvent.clouds.map { $0.id } incidentEvent.products.forEach { incidentProduct in guard let mostRecentUpdate = incidentProduct.history.last else { return } if mostRecentUpdate.status.isOpen { let status = mostRecentUpdate.severity.status let affectedIDs = affectedCloudIDs + [incidentProduct.id] affectedIDs.forEach { if let addedStatus = statuses[$0] { statuses[$0] = max(addedStatus, status) } else { statuses[$0] = status } } } } } return statuses } func updatedStatus(for service: AdobeStoreService) async throws -> ServiceStatusDescription { let updatedState = try await updatedState() let status = updatedState[service.id] switch status { case .good?: return ServiceStatusDescription(status: .good, message: "Available") case .minor?: return ServiceStatusDescription(status: .minor, message: "Minor issue(s)") case .major?: return ServiceStatusDescription(status: .major, message: "Major issue(s)") case .notice?: return ServiceStatusDescription(status: .notice, message: "Potential issue(s)") case .maintenance?: return ServiceStatusDescription(status: .maintenance, message: "Maintenance") case .some(.undetermined): return ServiceStatusDescription( status: .undetermined, message: loadErrorMessage ?? "Unexpected error" ) case .none: return ServiceStatusDescription(status: .good, message: "Available") } } } ================================================ FILE: stts/Services/Super/Apple.swift ================================================ // // Apple.swift // stts // import Foundation typealias Apple = BaseApple & RequiredServiceProperties & AppleStoreService class BaseApple: BaseIndependentService { private static var store = AppleStore( url: "https://www.apple.com/support/systemstatus/data/system_status_en_US.js" ) let url = URL(string: "https://www.apple.com/support/systemstatus/")! override func updateStatus() async throws { guard let realSelf = self as? Apple else { fatalError("BaseApple should not be used directly.") } statusDescription = try await BaseApple.store.updatedStatus(for: realSelf) } } ================================================ FILE: stts/Services/Super/AppleDeveloper.swift ================================================ // // AppleDeveloper.swift // stts // import Foundation typealias AppleDeveloper = BaseAppleDeveloper & RequiredServiceProperties & AppleStoreService class BaseAppleDeveloper: BaseIndependentService { private static var store = AppleStore( url: "https://www.apple.com/support/systemstatus/data/developer/system_status_en_US.js" ) let url = URL(string: "https://developer.apple.com/system-status/")! override func updateStatus() async throws { guard let realSelf = self as? AppleDeveloper else { fatalError("BaseAppleDeveloper should not be used directly.") } statusDescription = try await BaseAppleDeveloper.store.updatedStatus(for: realSelf) } } ================================================ FILE: stts/Services/Super/AppleStore.swift ================================================ // // AppleStore.swift // stts // import Foundation protocol AppleStoreService { var serviceName: String { get } } // AppleStore as in a store that holds the status of each of Apple's services, and not "Apple Store" class AppleStore: ServiceStore<[String: (ServiceStatus, String)]> { let url: URL init(url: String) { self.url = URL(string: url)! } override func retrieveUpdatedState() async throws -> [String: (ServiceStatus, String)] { let raw = try await rawString(from: url) guard let jsonData = raw.innerJSONString.data(using: .utf8) else { throw StatusUpdateError.decodingError(nil) } let responseData: AppleResponseData do { responseData = try JSONDecoder().decode(AppleResponseData.self, from: jsonData) } catch { throw StatusUpdateError.decodingError(error) } var serviceStatuses = [String: (ServiceStatus, String)]() responseData.services.forEach { if let worstEvent = $0.worstEvent { serviceStatuses[$0.serviceName] = (worstEvent.serviceStatus, worstEvent.realStatus.rawValue) } else { serviceStatuses[$0.serviceName] = (.good, "Available") } } return serviceStatuses } func updatedStatus(for service: AppleStoreService) async throws -> ServiceStatusDescription { let updatedState = try await updatedState() let status: ServiceStatus? let message: String? if service.serviceName == "*" { var lines: [String] = [] var worstStatus: (ServiceStatus, String)? for (serviceName, serviceStatusAndDescription) in updatedState { let serviceStatus = serviceStatusAndDescription.0 let serviceStatusDescription = serviceStatusAndDescription.1 if serviceStatus != .good { lines.append("\(serviceName): \(serviceStatusDescription)") } if serviceStatus > worstStatus?.0 ?? .undetermined { worstStatus = serviceStatusAndDescription } } status = worstStatus?.0 message = lines.isEmpty ? worstStatus?.1 : lines.joined(separator: "\n") } else { let worstStatus: (ServiceStatus, String)? = updatedState[service.serviceName] status = worstStatus?.0 message = worstStatus?.1 } return ServiceStatusDescription( status: status ?? .undetermined, message: message ?? loadErrorMessage ?? "Unexpected error" ) } } private struct AppleResponseData: Codable { struct Service: Codable { let serviceName: String let events: [Event] var worstEvent: Event? { return events.max { e1, e2 in e1.serviceStatus < e2.serviceStatus } } } enum EventStatus: String, Codable { case ongoing case resolved case upcoming case completed } enum EventType: String, Codable { case available = "Available" case outage = "Outage" case issue = "Issue" case performance = "Performance" case maintenance = "Maintenance" } struct Event: Codable { let statusType: EventType let eventStatus: EventStatus var realStatus: EventType { switch eventStatus { case .ongoing: return statusType case .resolved, .upcoming, .completed: return .available } } var serviceStatus: ServiceStatus { switch realStatus { case .available: return .good case .outage: return .major case .issue, .performance: return .minor case .maintenance: return .maintenance } } } let services: [Service] } ================================================ FILE: stts/Services/Super/Azure.swift ================================================ // // Azure.swift // stts // import Foundation typealias Azure = BaseAzure & RequiredServiceProperties & AzureStoreService class BaseAzure: BaseIndependentService { private static var store = AzureStore() let url = URL(string: "https://status.azure.com/en-us/status")! override func updateStatus() async throws { guard let realSelf = self as? Azure else { fatalError("BaseAzure should not be used directly.") } statusDescription = try await BaseAzure.store.updatedStatus(for: realSelf) } } ================================================ FILE: stts/Services/Super/AzureDevOps.swift ================================================ // // AzureDevOpsDevOps.swift // stts // import Foundation typealias AzureDevOps = BaseAzureDevOps & RequiredServiceProperties & AzureDevOpsStoreService class BaseAzureDevOps: BaseIndependentService { private static let store = AzureDevOpsStore() let url = URL(string: "https://status.dev.azure.com")! override func updateStatus() async throws { guard let realSelf = self as? AzureDevOps else { fatalError("BaseAzureDevOps should not be used directly.") } statusDescription = try await BaseAzureDevOps.store.updatedStatus(for: realSelf) } } ================================================ FILE: stts/Services/Super/AzureDevOpsStore.swift ================================================ // // AzureDevOpsStore.swift // stts // import Foundation import Kanna protocol AzureDevOpsStoreService { var serviceName: String { get } } private struct AzureDevOpsDataProviders: Codable { struct ResponseData: Codable { struct DataProvider: Codable { struct DataServiceStatus: Codable { struct DataService: Codable { struct DataGeography: Codable { let name: String let health: Int var status: ServiceStatus { switch health { case 1: return .major case 2: return .minor case 3: return .notice case 4: return .good default: return .undetermined } } } let id: String let geographies: [DataGeography] var status: ServiceStatus { return geographies.map { $0.status }.max() ?? .undetermined } } let services: [DataService] } let serviceStatus: DataServiceStatus } enum CodingKeys: String, CodingKey { case dataProvider = "ms.vss-status-web.public-status-data-provider" } let dataProvider: DataProvider } let data: ResponseData } class AzureDevOpsStore: ServiceStore<[String: ServiceStatus]> { private let url = URL(string: "https://status.dev.azure.com")! override func retrieveUpdatedState() async throws -> [String: ServiceStatus] { let doc = try await html(from: url) guard let json = doc.css("script#dataProviders").first?.innerHTML, let jsonData = json.data(using: .utf8) else { throw StatusUpdateError.decodingError(nil) } let providers: AzureDevOpsDataProviders do { providers = try JSONDecoder().decode(AzureDevOpsDataProviders.self, from: jsonData) } catch { throw StatusUpdateError.decodingError(error) } var statuses: [String: ServiceStatus] = [:] providers.data.dataProvider.serviceStatus.services.forEach { statuses[$0.id] = $0.status } return statuses } func updatedStatus(for service: AzureDevOpsStoreService) async throws -> ServiceStatusDescription { let updatedState = try await updatedState() let status: ServiceStatus? if service.serviceName == "*" { status = updatedState.values.max() } else { status = updatedState[service.serviceName] } switch status { case .good?: return ServiceStatusDescription(status: .good, message: "Healthy") case .minor?: return ServiceStatusDescription(status: .minor, message: "Degraded") case .major?: return ServiceStatusDescription(status: .major, message: "Unhealthy") case .notice?: return ServiceStatusDescription(status: .notice, message: "Advisory") default: return ServiceStatusDescription(status: .undetermined, message: loadErrorMessage ?? "Unexpected error") } } } ================================================ FILE: stts/Services/Super/AzureStore.swift ================================================ // // AzureStore.swift // stts // import Foundation import Kanna protocol AzureStoreService { var name: String { get } var zoneIdentifier: String { get } } class AzureStore: ServiceStore<[String: ServiceStatus]> { private let url = URL(string: "https://status.azure.com/en-us/status")! override func retrieveUpdatedState() async throws -> [String: ServiceStatus] { let doc = try await html(from: url) var statuses: [String: ServiceStatus] = [:] let zones = doc.css("li.zone[role=presentation]").compactMap { $0["data-zone-name"] } zones.forEach { identifier in let table = doc.css("table.status-table.region-status-table[data-zone-name=\(identifier)]").first table.map { guard let status = self.parseZoneTable($0) else { return } statuses[identifier] = status } } return statuses } func updatedStatus(for service: AzureStoreService) async throws -> ServiceStatusDescription { let updatedState = try await updatedState() let status: ServiceStatus? if service.zoneIdentifier == "*" { status = updatedState.values.max() } else { status = updatedState[service.zoneIdentifier] } switch status { case .good?: return ServiceStatusDescription(status: .good, message: "Good") case .minor?: return ServiceStatusDescription(status: .minor, message: "Warning") case .major?: return ServiceStatusDescription(status: .major, message: "Critical") case .notice?: return ServiceStatusDescription(status: .notice, message: "Information") default: return ServiceStatusDescription(status: .undetermined, message: loadErrorMessage ?? "Unexpected error") } } private func parseZoneTable(_ table: Kanna.XMLElement) -> ServiceStatus? { return table.css("use").compactMap { svgElement -> ServiceStatus? in guard let svgName = svgElement["xlink:href"] else { return nil } switch svgName { case "#svg-check": return .good case "#svg-health-warning": return .minor case "#svg-health-error": return .major case "#svg-health-information": return .notice default: return nil } }.max() } } ================================================ FILE: stts/Services/Super/BetterStackService.swift ================================================ // // BetterStackService.swift // stts // import Foundation import Kanna class BetterStackServiceDefinition: CodableServiceDefinition, ServiceDefinition { let providerIdentifier = "betterstack" func build() -> BaseService? { BetterStackService(self) } } class BetterStackService: Service { /* Version 1 (.heading-large): :root { /* light mode colors in RGB */ --color-green: 5, 150, 105; #059669 --color-red: 185, 28, 28; #b91c1c --color-blue: 3, 105, 161; #0369a1 --color-yellow: 217, 119, 6; #d97706 } There are no class names or any indication about the service status since the status icon is sent as inline SVG. However, we can use the fill color to extrapolate the status. Version 2 (.heading-small): The SVG element has a CSS class indicating the status color: .text-statuspage-green, .text-statuspage-red, .text-statuspage-blue, .text-statuspage-yellow */ private enum StatusIconFillColor: String { case green = "#059669" case red = "#b91c1c" case blue = "#0369a1" case yellow = "#d97706" var serviceStatus: ServiceStatus { switch self { case .green: return .good case .yellow: return .minor case .red: return .major case .blue: return .maintenance } } } private enum StatusIconClass: String { case green = "text-statuspage-green" case red = "text-statuspage-red" case blue = "text-statuspage-blue" case yellow = "text-statuspage-yellow" var serviceStatus: ServiceStatus { switch self { case .green: return .good case .yellow: return .minor case .red: return .major case .blue: return .maintenance } } } let name: String let url: URL init(_ definition: BetterStackServiceDefinition) { name = definition.name url = definition.url } override func updateStatus() async throws { let doc = try await html(from: url) if let heading = doc.css(".heading-large").first { try updateStatusV1(heading: heading) } else if let heading = doc.css(".heading-small").first { try updateStatusV2(heading: heading) } else { throw StatusUpdateError.decodingError(nil) } } private func updateStatusV1(heading: Kanna.XMLElement) throws { guard let statusMessage = heading.text?.trimmingCharacters(in: .whitespacesAndNewlines), let statusIconFillColorString = heading.parent?.css("svg").first?.css("path").first?["fill"], let statusIconFillColor = StatusIconFillColor(rawValue: statusIconFillColorString.lowercased()) else { throw StatusUpdateError.decodingError(nil) } statusDescription = ServiceStatusDescription( status: statusIconFillColor.serviceStatus, message: statusMessage ) } private func updateStatusV2(heading: Kanna.XMLElement) throws { guard let statusMessage = heading.text?.trimmingCharacters(in: .whitespacesAndNewlines), let svgClassAttr = heading.parent?.css("svg").first?.className else { throw StatusUpdateError.decodingError(nil) } let svgClasses = svgClassAttr.components(separatedBy: .whitespaces) guard let statusIconClass = svgClasses.lazy.compactMap({ StatusIconClass(rawValue: $0) }).first else { throw StatusUpdateError.decodingError(nil) } statusDescription = ServiceStatusDescription( status: statusIconClass.serviceStatus, message: statusMessage ) } } ================================================ FILE: stts/Services/Super/BetterUptimeService.swift ================================================ // // BetterUptimeService.swift // stts // import Foundation import Kanna class BetterUptimeServiceDefinition: CodableServiceDefinition, ServiceDefinition { let providerIdentifier = "betteruptime" func build() -> BaseService? { BetterUptimeService(self) } } class BetterUptimeService: Service { private enum BetterUptimeStatus: String, CaseIterable { case operational case degraded case downtime case maintenance case notMonitored = "not-monitored" var serviceStatus: ServiceStatus { switch self { case .operational: return .good case .degraded: return .minor case .downtime: return .major case .maintenance: return .maintenance case .notMonitored: return .notice } } var iconCSSClass: String { switch self { case .operational: return "text-statuspage-green" case .degraded: return "text-statuspage-yellow" case .downtime: return "text-statuspage-red" case .maintenance: return "text-statuspage-blue" case .notMonitored: return "not-supported-in-v2-maybe?-make-an-issue-if-wrong" } } } let name: String let url: URL init(_ definition: BetterUptimeServiceDefinition) { name = definition.name url = definition.url } override func updateStatus() async throws { let doc = try await html(from: url) let status: ServiceStatus if let overviewElement = doc.css(".status-page__overview").first { // v1 page if let iconElement = overviewElement.css(".status-page__overview-icon").first { status = self.status(from: iconElement)?.serviceStatus ?? .undetermined } else { status = .undetermined } } else if let headerIconElement = doc.css("h1 svg").first { // v2 page status = self.status(fromV2Icon: headerIconElement)?.serviceStatus ?? .undetermined } else { throw StatusUpdateError.decodingError(nil) } let message = doc.css("h1").first?.content? .trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) ?? "Unexpected response" statusDescription = ServiceStatusDescription(status: status, message: message) } private func status(from element: Kanna.XMLElement) -> BetterUptimeStatus? { guard let className = element.className, !className.isEmpty else { return nil } for statusCase in BetterUptimeStatus.allCases { if className.contains(statusCase.rawValue) { return statusCase } } return nil } private func status(fromV2Icon element: Kanna.XMLElement) -> BetterUptimeStatus? { guard let className = element.className, !className.isEmpty else { return nil } for statusCase in BetterUptimeStatus.allCases { if className.contains(statusCase.iconCSSClass) { return statusCase } } return nil } } ================================================ FILE: stts/Services/Super/CStateService.swift ================================================ // // CStateService.swift // stts // import Foundation class CStateServiceDefinition: CodableServiceDefinition, ServiceDefinition { let providerIdentifier = "cstate" func build() -> BaseService? { CStateService(self) } } class CStateService: Service { private enum CStateStatus: String, Codable { // https://github.com/cstate/cstate/blob/master/layouts/index.json case ok case down case disrupted case notice var description: String { // https://github.com/cstate/cstate/blob/master/i18n/en.yaml#L17-L24 switch self { case .ok: return "No issues detected" case .down: return "Experiencing major issues" case .disrupted: return "Experiencing disruptions" case .notice: return "Please read announcement" } } var serviceStatus: ServiceStatus { switch self { case .ok: return .good case .down: return .minor case .disrupted: return .major case .notice: return .notice } } } private struct Response: Codable { struct System: Codable { let name: String let status: CStateStatus? } let summaryStatus: CStateStatus let systems: [System] } let name: String let url: URL init(_ definition: CStateServiceDefinition) { name = definition.name url = definition.url } override func updateStatus() async throws { let statusURL = url.appendingPathComponent("index.json") let response = try await decoded(Response.self, from: statusURL) statusDescription = ServiceStatusDescription( status: response.summaryStatus.serviceStatus, message: message(from: response) ) } private func message(from response: Response) -> String { let affectedSystems = response.systems.filter { $0.status != nil && $0.status != .ok } guard !affectedSystems.isEmpty else { return response.summaryStatus.description } var lines: [String] = [] lines.append(response.summaryStatus.description) lines.append(contentsOf: affectedSystems.map { "* \($0.name)"}) return lines.joined(separator: "\n") } } ================================================ FILE: stts/Services/Super/CachetService.swift ================================================ // // CachetService.swift // stts // import Foundation class CachetServiceDefinition: CodableServiceDefinition, ServiceDefinition { let providerIdentifier = "cachet" func build() -> BaseService? { CachetService(self) } } class CachetService: Service { private enum ComponentStatus: Int, ComparableStatus { // https://docs.cachethq.io/docs/component-statuses case operational = 1 case performanceIssues = 2 case partialOutage = 3 case majorOutage = 4 var description: String { switch self { case .operational: return "Operational" case .performanceIssues: return "Performance Issues" case .partialOutage: return "Partial Outage" case .majorOutage: return "Major Outage" } } var serviceStatus: ServiceStatus { switch self { case .operational: return .good case .performanceIssues: return .notice case .partialOutage: return .minor case .majorOutage: return .major } } } let name: String let url: URL init(_ definition: CachetServiceDefinition) { name = definition.name url = definition.url } override func updateStatus() async throws { let apiComponentsURL = url.appendingPathComponent("api/v1/components") let data = try await self.rawData(from: apiComponentsURL) let json = try? JSONSerialization.jsonObject(with: data, options: []) guard let components = (json as? [String: Any])?["data"] as? [[String: Any]], !components.isEmpty else { throw StatusUpdateError.decodingError(nil) } let worstStatus = components .compactMap({ $0["status"] as? Int }) .compactMap(ComponentStatus.init(rawValue:)) .max() statusDescription = ServiceStatusDescription( status: worstStatus?.serviceStatus ?? .undetermined, message: worstStatus?.description ?? "Unexpected response" ) } } ================================================ FILE: stts/Services/Super/ExanaService.swift ================================================ // // ExanaService.swift // stts // import Foundation import Kanna class ExanaServiceDefinition: CodableServiceDefinition, ServiceDefinition { enum ExtraKeys: String, CodingKey { case id } /// Service ID let id: String let providerIdentifier = "exana" required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: ExtraKeys.self) id = try container.decode(String.self, forKey: .id) try super.init(from: decoder) } override func encode(to encoder: Encoder) throws { try super.encode(to: encoder) var container = encoder.container(keyedBy: ExtraKeys.self) try container.encode(id, forKey: .id) } func build() -> BaseService? { ExanaService(self) } } class ExanaService: Service { private enum ExanaStatus: String { case operational case monitoring var serviceStatus: ServiceStatus { switch self { case .operational: return .good case .monitoring: return .maintenance } } } let id: String let name: String let url: URL init(_ definition: ExanaServiceDefinition) { id = definition.id name = definition.name url = definition.url } override func updateStatus() async throws { let doc = try await html(from: url) guard let jwt = doc.css("meta[name=jwt]").first?["content"] else { throw StatusUpdateError.custom("Couldn't get authorization") } try await getStatus(authorization: jwt) } func getStatus(authorization: String) async throws { let params: [String: Any] = [ "method": "components.query", "params": [ "serviceId": id ], "id": String.init(repeating: "a", count: 40), "jsonrpc": "2.0" ] guard let jsonData = try? JSONSerialization.data(withJSONObject: params, options: []) else { throw StatusUpdateError.custom("Couldn't serialize parameters for ExanaService request") } var request = URLRequest(url: URL(string: "https://statuspage.exana.io/api/components.query")!) request.setValue(authorization, forHTTPHeaderField: "Authorization") request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.httpMethod = "POST" request.httpBody = jsonData let data = try await rawData(for: request) guard let json = try? JSONSerialization.jsonObject(with: data, options: []), let jsonRoot = json as? [String: Any], let result = jsonRoot["result"] as? [String: Any], let components = result["components"] as? [[String: Any]] else { throw StatusUpdateError.decodingError(nil) } var downComponents = [[String: Any]]() let componentStatuses: [ServiceStatus] = components.compactMap { guard let statusString = ($0["status"] as? String)?.lowercased() else { return nil } let resultStatus = ExanaStatus(rawValue: statusString)?.serviceStatus ?? .major if resultStatus != .good { downComponents.append($0) } return resultStatus } let maxStatus: ServiceStatus = componentStatuses.max() ?? .undetermined let message: String switch maxStatus { case .good: message = "Operational" case .undetermined: message = "Unexpected response" default: message = downComponents.map { $0["name"] as? String } .compactMap { $0 } .joined(separator: ", ") } statusDescription = ServiceStatusDescription(status: maxStatus, message: message) } } ================================================ FILE: stts/Services/Super/FirebaseService.swift ================================================ // // Firebase.swift // stts // import Foundation typealias FirebaseService = BaseFirebaseService & RequiredServiceProperties & RequiredFirebaseProperties protocol RequiredFirebaseProperties: FirebaseStatusDashboardStoreService { var name: String { get } var dashboardName: String { get } } extension RequiredFirebaseProperties { var dashboardName: String { let prefix = "Firebase " guard let prefixRange = name.range(of: prefix), prefixRange.lowerBound.utf16Offset(in: name) == 0 else { return name } return name.replacingCharacters(in: prefixRange, with: "") } } private let firebaseDashboardURL = URL(string: "https://status.firebase.google.com")! class BaseFirebaseService: BaseIndependentService { private static var store = FirebaseStatusDashboardStore(url: firebaseDashboardURL) let url = firebaseDashboardURL override func updateStatus() async throws { guard let realSelf = self as? FirebaseService else { fatalError("BaseFirebaseService should not be used directly.") } statusDescription = try await BaseFirebaseService.store.updatedStatus(for: realSelf) } } ================================================ FILE: stts/Services/Super/FirebaseStatusDashboardStore.swift ================================================ // // FirebaseStatusDashboardStore.swift // stts // import Foundation import Kanna protocol FirebaseStatusDashboardStoreService { var name: String { get } var dashboardName: String { get } } extension FirebaseStatusDashboardStoreService { var dashboardName: String { return name } } class FirebaseStatusDashboardStore: ServiceStore<[String: ServiceStatus]> { private var dashboardURL: URL init(url: URL) { dashboardURL = url } override func retrieveUpdatedState() async throws -> [String: ServiceStatus] { let doc = try await html(from: dashboardURL) var statuses: [String: ServiceStatus] = [:] var badStatuses: [ServiceStatus] = [] for tr in doc.css(".main-dashboard-table tr") { guard let (name, status) = self.parseDashboardRow(tr) else { continue } statuses[name] = status if status != .good && status != .undetermined { badStatuses.append(status) } } let generalStatus: ServiceStatus if badStatuses.count > 2 { generalStatus = .major } else if badStatuses.count > 0 { generalStatus = .minor } else { generalStatus = .good } statuses["_general"] = generalStatus return statuses } func updatedStatus(for service: FirebaseStatusDashboardStoreService) async throws -> ServiceStatusDescription { let updatedState = try await updatedState() let status: ServiceStatus? if type(of: service) == Firebase.self { status = updatedState["_general"] } else { let expandedDashboardName = "Firebase \(service.dashboardName)" status = updatedState[service.dashboardName] ?? updatedState[expandedDashboardName] } switch status { case .good?: return ServiceStatusDescription(status: .good, message: "Normal Operations") case .minor?: return ServiceStatusDescription(status: .minor, message: "Service Disruption") case .major?: return ServiceStatusDescription(status: .major, message: "Service Outage") default: return ServiceStatusDescription(status: .undetermined, message: loadErrorMessage ?? "Unexpected error") } } private func parseDashboardRow(_ tr: Kanna.XMLElement) -> (String, ServiceStatus)? { let rawName = tr.css(".product-name").first?.text?.trimmingCharacters(in: .whitespacesAndNewlines) let sanitizedName = rawName? .components(separatedBy: .newlines).first? .trimmingCharacters(in: .whitespacesAndNewlines) guard let name = sanitizedName else { return nil } if tr.css("svg.psd__status-icon.psd__available").count > 0 { return (name, .good) } else if tr.css("svg.psd__status-icon.psd__disruption").count > 0 { return (name, .minor) } else if tr.css("svg.psd__status-icon.psd__outage").count > 0 { return (name, .major) } else if tr.css("svg.psd__status-icon.psd__information").count > 0 { return (name, .notice) } else { return (name, .undetermined) } } } ================================================ FILE: stts/Services/Super/GoogleCloudPlatform.swift ================================================ // // GoogleCloudPlatform.swift // stts // import Foundation typealias GoogleCloudPlatform = BaseGoogleCloudPlatform & RequiredServiceProperties & GoogleStatusDashboardStoreService private let gcpDashboardURL = URL(string: "https://status.cloud.google.com")! class BaseGoogleCloudPlatform: BaseIndependentService { private static var store = GoogleStatusDashboardStore(url: gcpDashboardURL) let url = gcpDashboardURL override func updateStatus() async throws { guard let realSelf = self as? GoogleCloudPlatform else { fatalError("BaseGoogleCloudPlatform should not be used directly.") } statusDescription = try await BaseGoogleCloudPlatform.store.updatedStatus(for: realSelf) } } ================================================ FILE: stts/Services/Super/GoogleStatusDashboardStore.swift ================================================ // // GoogleStatusDashboardStore.swift // stts // import Foundation import Kanna protocol GoogleStatusDashboardStoreService { var name: String { get } var dashboardName: String { get } } extension GoogleStatusDashboardStoreService { var dashboardName: String { return name } } class GoogleStatusDashboardStore: ServiceStore<[String: ServiceStatus]> { private let dashboardURL: URL init(url: URL) { dashboardURL = url } override func retrieveUpdatedState() async throws -> [String: ServiceStatus] { let doc = try await html(from: dashboardURL) var statuses: [String: ServiceStatus] = [:] var badStatuses: [ServiceStatus] = [] for tr in doc.css("psd-regional-table tbody tr") { guard let (name, status) = self.parseDashboardRow(tr) else { continue } statuses[name] = status if status != .good && status != .undetermined { badStatuses.append(status) } } let generalStatus: ServiceStatus if badStatuses.count > 2 { generalStatus = .major } else if badStatuses.count > 0 { generalStatus = .minor } else { generalStatus = .good } statuses["_general"] = generalStatus return statuses } func updatedStatus(for service: GoogleStatusDashboardStoreService) async throws -> ServiceStatusDescription { let updatedState = try await updatedState() let status: ServiceStatus? if type(of: service) == GoogleCloudPlatformAll.self { status = updatedState["_general"] } else { status = updatedState[service.dashboardName] } switch status { case .good: return ServiceStatusDescription(status: .good, message: "Available") case .notice: return ServiceStatusDescription(status: .notice, message: "Service information") case .minor: return ServiceStatusDescription(status: .minor, message: "One or more regions affected") case .major: return ServiceStatusDescription(status: .major, message: "Service outage") default: return ServiceStatusDescription(status: .undetermined, message: loadErrorMessage ?? "Unexpected error") } } private func parseDashboardRow(_ tr: Kanna.XMLElement) -> (String, ServiceStatus)? { let rawName = tr.css("th").first?.text?.trimmingCharacters(in: .whitespacesAndNewlines) let sanitizedName = rawName? .components(separatedBy: .newlines).first? .trimmingCharacters(in: .whitespacesAndNewlines) guard let name = sanitizedName else { return nil } let iconClassNames = tr.css("psd-status-icon svg").compactMap { $0.className } guard !iconClassNames.isEmpty else { // Unexpected return nil } let statuses: [ServiceStatus] = iconClassNames.map { if $0.contains("__available") { return .good } else if $0.contains("__information") { return .notice } else if $0.contains("__warning") || $0.contains("__disruption") { return .minor } else if $0.contains("__outage") { return .major } else { return .undetermined } } let max = statuses.max() ?? .undetermined return (name, max) } } ================================================ FILE: stts/Services/Super/IncidentIOService.swift ================================================ // // IncidentIOService.swift // stts // import Foundation import Kanna class IncidentIOServiceDefinition: CodableServiceDefinition, ServiceDefinition { let providerIdentifier = "incidentio" func build() -> BaseService? { IncidentIOService(self) } } class IncidentIOService: Service { let name: String let url: URL init(_ definition: IncidentIOServiceDefinition) { name = definition.name url = definition.url } private func serviceStatus(fromIconSuffix suffix: String) -> ServiceStatus { switch suffix { case "operational": return .good case "degraded-performance", "partial-outage": return .minor case "full-outage": return .major case "under-maintenance": return .maintenance default: return .undetermined } } private func iconSuffix(fromClassName className: String) -> String? { guard let range = className.range(of: "text-icon-") else { return nil } return String(className[range.upperBound...]).components(separatedBy: " ").first } override func updateStatus() async throws { let doc = try await html(from: url) guard let headsUp = doc.css("[data-testid='heads-up']").first else { statusDescription = ServiceStatusDescription(status: .good, message: "") return } guard let firstLi = headsUp.css("li").first else { throw StatusUpdateError.parseError(nil) } let statusText = firstLi.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "" let liSvgClass = firstLi.css("svg").first?.className ?? "" let liIconSuffix = iconSuffix(fromClassName: liSvgClass) var incidentTitles: [String] = [] var incidentStatuses: [ServiceStatus] = [] for anchor in headsUp.css("a") { guard let href = anchor["href"], href.hasPrefix("/incidents/") else { continue } let title = anchor.css(".items-center").first?.text? .trimmingCharacters(in: .whitespacesAndNewlines) ?? "" let svgClass = anchor.css("svg").first?.className ?? "" if let suffix = iconSuffix(fromClassName: svgClass) { incidentStatuses.append(serviceStatus(fromIconSuffix: suffix)) } if !title.isEmpty { incidentTitles.append(title) } } let overallStatus: ServiceStatus if let suffix = liIconSuffix { overallStatus = serviceStatus(fromIconSuffix: suffix) } else { overallStatus = incidentStatuses.max() ?? .undetermined } let message: String if incidentTitles.isEmpty { message = statusText } else { let lines = incidentTitles.map { "* \($0)" }.joined(separator: "\n") message = statusText.isEmpty ? lines : "\(statusText)\n\(lines)" } statusDescription = ServiceStatusDescription(status: overallStatus, message: message) } } ================================================ FILE: stts/Services/Super/IndependentService.swift ================================================ // // IndependentService.swift // stts // import Foundation class IndependentServiceDefinition: CodableServiceDefinition, ServiceDefinition { enum ExtraKeys: String, CodingKey { case className = "class_name" } let className: String? let providerIdentifier = "independent" required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: ExtraKeys.self) className = try container.decodeIfPresent(String.self, forKey: .className) try super.init(from: decoder) } override func encode(to encoder: Encoder) throws { try super.encode(to: encoder) var container = encoder.container(keyedBy: ExtraKeys.self) try container.encode(className, forKey: .className) } init?(fromClassName className: String) { let globalTypeName = "stts.\(className)" let klass = NSClassFromString(globalTypeName) as? BaseIndependentService.Type guard let service = klass?.init() as? Service else { assertionFailure("Failed to initialize service definition from class name") return nil } self.className = className super.init( name: service.name, url: service.url, isCategory: service is ServiceCategory, isSubService: service is SubService ) } private lazy var overriddenLegacyIdentifiers: Set = { var set = oldNames ?? .init() if let className { // Before JSON definitions, we were using class names as identifiers. Try to replicate that now. set.insert(className) } return set }() override var legacyIdentifiers: Set { overriddenLegacyIdentifiers } func build() -> BaseService? { let typeName = className ?? alphanumericName let globalTypeName = "stts.\(typeName)" guard let service = (NSClassFromString(globalTypeName) as? BaseIndependentService.Type)?.init() else { assertionFailure("Failed to initialize service from class name") return nil } return service } } typealias IndependentService = BaseIndependentService & RequiredServiceProperties class BaseIndependentService: BaseService { public required override init() {} } ================================================ FILE: stts/Services/Super/InstatusService.swift ================================================ // // InstatusService.swift // stts // import Foundation import Kanna class InstatusServiceDefinition: CodableServiceDefinition, ServiceDefinition { let providerIdentifier = "instatus" func build() -> BaseService? { InstatusService(self) } } class InstatusService: Service { private struct Site: Codable { let status: Status let components: [Component] enum Status: String, Codable { case up = "UP" case hasIssues = "HASISSUES" } } private struct Component: Codable { let name: Name let status: Status? let children: [Component]? /// The status of the current component and its children if any var effectiveStatus: ServiceStatus { if let children, let firstChild = children.first { return children.map { $0.effectiveStatus }.max() ?? firstChild.effectiveStatus } else if let status { return status.status } else { return .undetermined } } var affectedComponentsNames: [String] { if let children, !children.isEmpty { return children .filter { $0.status != nil && $0.status != .operational } .flatMap { $0.affectedComponentsNames } .map { "\(name): \($0)"} } else if status != nil, status != .operational { return [name.default] } else { return [] } } struct Name: Codable { let `default`: String } enum Status: String, Codable { case operational = "OPERATIONAL" case underMaintenance = "UNDERMAINTENANCE" case degradedPerformance = "DEGRADEDPERFORMANCE" case partialOutage = "PARTIALOUTAGE" case minorOutage = "MINOROUTAGE" case majorOutage = "MAJOROUTAGE" var status: ServiceStatus { switch self { case .operational: return .good case .underMaintenance: return .maintenance case .degradedPerformance: return .notice case .partialOutage, .minorOutage: return .minor case .majorOutage: return .major } } } } private struct Incident: Codable { let name: Name let status: Status var isUnresolved: Bool { switch status { case .investigating, .identified, .monitoring: return true case .resolved: return false } } struct Name: Codable { let `default`: String } enum Status: String, Codable { case investigating = "INVESTIGATING" case identified = "IDENTIFIED" case monitoring = "MONITORING" case resolved = "RESOLVED" } } private struct InstatusData: Codable { let site: Site let activeIncidents: [Incident] } let name: String let url: URL init(_ definition: InstatusServiceDefinition) { name = definition.name url = definition.url } override func updateStatus() async throws { let doc = try await html(from: url) var statusData: InstatusData? let scriptTags = doc.css("script") for scriptTag in scriptTags { guard let rawHTML = scriptTag.innerHTML else { continue } if rawHTML.contains("activeIncidents") { // swiftlint:disable:next force_try let regularExpression = try! NSRegularExpression( pattern: "\\{.*\\}", options: [.caseInsensitive, .dotMatchesLineSeparators] ) guard let firstMatch = regularExpression.firstMatch( in: rawHTML, range: NSRange(location: 0, length: (rawHTML as NSString).length) ) else { continue } let json = (rawHTML as NSString).substring(with: firstMatch.range).unescaped guard let jsonData = json.data(using: .utf8) else { continue } let dictionary = try? JSONSerialization.jsonObject(with: jsonData) as? [String: Any] let children = dictionary?["children"] as? [Any] if let dataObject = children?.last as? [String: Any], let dataObjectJSON = try? JSONSerialization.data(withJSONObject: dataObject) { statusData = try? JSONDecoder().decode(InstatusData.self, from: dataObjectJSON) if statusData != nil { break } } } } guard let statusData else { throw StatusUpdateError.decodingError(nil) } setStatus(from: statusData) } private func setStatus(from statusData: InstatusData) { let status = serviceStatus( for: statusData.site, components: statusData.site.components ) // Set the message by combining the unresolved incident names let unresolvedIncidents = statusData.activeIncidents.filter { $0.isUnresolved } if !unresolvedIncidents.isEmpty { let prefix = unresolvedIncidents.count > 1 ? "* " : "" let message = unresolvedIncidents.map { "\(prefix)\($0.name.default)" }.joined(separator: "\n") statusDescription = ServiceStatusDescription(status: status, message: message) return } // Or from affected the component names let affectedComponents = statusData.site.components.flatMap { $0.affectedComponentsNames } if !affectedComponents.isEmpty { let message = affectedComponents.joined(separator: "\n") statusDescription = ServiceStatusDescription(status: status, message: message) return } // Fallback to the status description let message: String switch statusData.site.status { case .up: message = "All systems operational" case .hasIssues: message = "Experiencing issues" } statusDescription = ServiceStatusDescription(status: status, message: message) } private func serviceStatus( for site: Site, components: [Component] ) -> ServiceStatus { switch site.status { case .up: return .good case .hasIssues: return components.map { $0.effectiveStatus }.max() ?? .undetermined } } } ================================================ FILE: stts/Services/Super/LambStatusService.swift ================================================ // // LambStatusService.swift // stts // import Foundation class LambStatusServiceDefinition: CodableServiceDefinition, ServiceDefinition { let providerIdentifier = "lamb" func build() -> BaseService? { LambStatusService(self) } } class LambStatusService: Service { // According to // https://github.com/ks888/LambStatus/blob/ba950df3241ac9143e03411d6c1a06d126cc0180/packages/frontend/src/utils/status.js#L1 private enum LambStatus: String, Codable { case operational = "Operational" case underMaintenance = "Under Maintenance" case degradedPerformance = "Degraded Performance" case partialOutage = "Partial Outage" case majorOutage = "Major Outage" var serviceStatus: ServiceStatus { switch self { case .operational: return .good case .underMaintenance: return .maintenance case .degradedPerformance, .partialOutage: return .minor case .majorOutage: return .major } } } private struct LambComponent: Codable { let componentID: String let name: String let status: LambStatus } let name: String let url: URL init(_ definition: LambStatusServiceDefinition) { name = definition.name url = definition.url } override func updateStatus() async throws { let components = try await decoded( [LambComponent].self, from: url.appendingPathComponent("api").appendingPathComponent("components") ) guard !components.isEmpty else { throw StatusUpdateError.decodingError(nil) } let worstComponent = components.max(by: { (one, two) -> Bool in one.status.serviceStatus < two.status.serviceStatus })! // We checked that it's not empty above statusDescription = ServiceStatusDescription( status: worstComponent.status.serviceStatus, message: worstComponent.status.rawValue ) } } ================================================ FILE: stts/Services/Super/MiroService.swift ================================================ // // MiroService.swift // stts // import Foundation class MiroServiceDefinition: IncidentIOServiceDefinition { override func build() -> BaseService? { MiroService(self) } } class MiroService: IncidentIOService {} ================================================ FILE: stts/Services/Super/PagerDutyService.swift ================================================ // // PagerDutyService.swift // stts // import Foundation import Kanna typealias PagerDutyService = BasePagerDutyService & RequiredServiceProperties & RequiredPagerDutyProperties protocol RequiredPagerDutyProperties {} class BasePagerDutyService: BaseIndependentService { private struct PagerDutyDataV1: Codable { struct Summary: Codable { enum CodingKeys: String, CodingKey { case openIncidents = "open_incidents" } struct Incident: Codable { struct Update: Codable { enum Severity: String, Codable { case allGood = "all_good" case minor case major case maintenance var serviceStatus: ServiceStatus { switch self { case .allGood: return .good case .minor: return .minor case .major: return .major case .maintenance: return .maintenance } } } let severity: Severity } let title: String let updates: [Update] } let openIncidents: [Incident] } let summary: Summary } private struct PagerDutyDataV2: Codable { struct Layout: Codable { struct LayoutSettings: Codable { struct StatusPage: Codable { let globalStatusHeadline: String let globalStatusHeadlineHasError: Bool let linkText: String let linkUrlText: String } let statusPage: StatusPage } let layoutSettings: LayoutSettings enum CodingKeys: String, CodingKey { case layoutSettings = "layout_settings" } } let layout: Layout enum CodingKeys: String, CodingKey { case layout } } override func updateStatus() async throws { guard let realSelf = self as? PagerDutyService else { fatalError("BasePagerDutyService should not be used directly.") } let doc = try await html(from: realSelf.url) guard let json = doc.css("script#data").first?.innerHTML, let jsonData = Data(json.utf8) as Data? else { throw StatusUpdateError.parseError(nil) } if let data = try? JSONDecoder().decode(PagerDutyDataV1.self, from: jsonData) { updateStatus(from: data) } else if let data = try? JSONDecoder().decode(PagerDutyDataV2.self, from: jsonData) { updateStatus(from: data) } else { throw StatusUpdateError.parseError(nil) } } private func updateStatus(from data: PagerDutyDataV1) { let incidents = data.summary.openIncidents switch incidents.count { case 0: statusDescription = ServiceStatusDescription(status: .good, message: "No known issue") case 1: statusDescription = ServiceStatusDescription( status: incidents[0].updates.first?.severity.serviceStatus ?? .good, message: incidents[0].title ) default: statusDescription = ServiceStatusDescription( status: incidents.map { $0.updates.first?.severity.serviceStatus ?? .good }.max() ?? .good, message: incidents.map { "- \($0.title)" }.joined(separator: "\n") ) } } private func updateStatus(from data: PagerDutyDataV2) { let status: ServiceStatus = data.layout.layoutSettings.statusPage.globalStatusHeadlineHasError ? .minor : .good statusDescription = ServiceStatusDescription( status: status, message: data.layout.layoutSettings.statusPage.globalStatusHeadline ) } } ================================================ FILE: stts/Services/Super/PayPal.swift ================================================ // // PayPal.swift // stts // import Foundation typealias PayPal = BasePayPal & RequiredServiceProperties & RequiredPayPalProperties enum PayPalEnvironment: String { case sandbox case production } enum PayPalComponent { case product(PayPalEnvironment) case api(PayPalEnvironment) var category: String { switch self { case .product: return "product" case .api: return "api" } } var environment: PayPalEnvironment { switch self { case let .product(environment): return environment case let .api(environment): return environment } } } protocol RequiredPayPalProperties { var component: PayPalComponent { get } } class BasePayPal: BaseIndependentService { private enum PayPalStatus: String, ComparableStatus { case operational case underMaintenance = "under_maintenance" case serviceDisruption = "service_disruption" case serviceOutage = "service_outage" case informational var serviceStatus: ServiceStatus { switch self { case .operational, .informational: return .good case .underMaintenance: return .maintenance case .serviceDisruption: return .minor case .serviceOutage: return .major } } var statusMessage: String { switch self { case .operational, .informational: return "Operational" case .underMaintenance: return "Under Maintenance" case .serviceDisruption: return "Service Disruption" case .serviceOutage: return "Service Outage" } } } var url: URL { guard let paypal = self as? PayPal else { fatalError("BasePayPal should not be used directly") } var components = URLComponents() components.scheme = "https" components.host = "www.paypal-status.com" components.path = "/\(paypal.component.category)/\(paypal.component.environment.rawValue)" return components.url! } override func updateStatus() async throws { guard let realSelf = self as? PayPal else { fatalError("BasePayPal should not be used directly.") } let apiURL = URL(string: "https://www.paypal-status.com/api/v1/components")! let data = try await rawData(from: apiURL) guard let dict = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any], let resultArray = dict["result"] as? [[String: Any]] else { throw StatusUpdateError.decodingError(nil) } let statuses = resultArray.compactMap { status(fromResultItem: $0, component: realSelf.component) } guard let worstStatus = statuses.max() else { throw StatusUpdateError.decodingError(nil) } statusDescription = ServiceStatusDescription( status: worstStatus.serviceStatus, message: worstStatus.statusMessage ) } private func status(fromResultItem resultItem: [String: Any], component: PayPalComponent) -> PayPalStatus? { guard let categoryDict = resultItem["category"] as? [String: Any], categoryDict["name"] as? String == component.category, let statusDict = resultItem["status"] as? [String: String], let statusString = statusDict[component.environment.rawValue] else { return nil } let sanitizedStatusString = statusString.replacingOccurrences(of: " ", with: "_").lowercased() return PayPalStatus(rawValue: sanitizedStatusString) } } ================================================ FILE: stts/Services/Super/PlayStationNetwork.swift ================================================ // // PlayStationNetwork.swift // stts // import Foundation typealias PlayStationNetwork = BasePlayStationNetwork & RequiredServiceProperties & RequiredPlayStationNetworkProperties enum PlayStationNetworkRegion: String { // from app.json case scea case scee case sceja var apiURL: URL { var components = URLComponents() components.scheme = "https" components.host = "status.playstation.com" components.path = "/data/statuses/region/\(rawValue.uppercased()).json" return components.url! } } protocol RequiredPlayStationNetworkProperties { var region: PlayStationNetworkRegion { get } } class BasePlayStationNetwork: BaseIndependentService { struct Response: Codable { struct Status: Codable { enum StatusType: String, Codable { case outage = "Outage" case degraded = "Degraded" case maintenance = "Maintenance" case ok = "OK" } let statusId: String let statusType: StatusType } let regionName: String let status: [Status] } let url = URL(string: "https://status.playstation.com")! override func updateStatus() async throws { guard let realSelf = self as? PlayStationNetwork else { fatalError("BasePlayStationNetwork should not be used directly.") } let response = try await decoded(Response.self, from: realSelf.region.apiURL) let statusType = response.status.first?.statusType ?? .ok let status: ServiceStatus let message: String switch statusType { case .degraded: status = .minor message = "Some services are experiencing issues." case .outage: status = .major message = "Some services are experiencing issues." case .maintenance: status = .maintenance message = "Some services are undergoing scheduled maintenance." case .ok: status = .good message = "All services are up and running." } statusDescription = ServiceStatusDescription(status: status, message: message) } } ================================================ FILE: stts/Services/Super/Salesforce.swift ================================================ // // Salesforce.swift // Salesforce // import Foundation typealias Salesforce = BaseSalesforce & RequiredServiceProperties & SalesforceStoreService & InheritsSalesforceCategory typealias BaseSalesforceCategory = BaseSalesforce & InheritsSalesforceCategory protocol InheritsSalesforceCategory { static var store: SalesforceStore { get } } extension InheritsSalesforceCategory { var store: SalesforceStore { Self.store } } class BaseSalesforce: BaseIndependentService { override func updateStatus() async throws { guard let realSelf = self as? Salesforce else { fatalError("BaseSalesforce should not be used directly.") } statusDescription = try await realSelf.store.updatedStatus(for: realSelf) } } ================================================ FILE: stts/Services/Super/SalesforceCategories.swift ================================================ // This file is generated by generate_salesforce_services.swift and should not be modified manually. // swiftlint:disable superfluous_disable_command type_name import Foundation typealias SalesforceB2CCommerceCloud = BaseSalesforceB2CCommerceCloud & RequiredServiceProperties & SalesforceStoreService class BaseSalesforceB2CCommerceCloud: BaseSalesforceCategory { static var store = SalesforceStore(key: "B2C_Commerce_Cloud") let url = URL(string: "https://status.salesforce.com/products/B2C_Commerce_Cloud")! } typealias SalesforceExperienceCloud = BaseSalesforceExperienceCloud & RequiredServiceProperties & SalesforceStoreService class BaseSalesforceExperienceCloud: BaseSalesforceCategory { static var store = SalesforceStore(key: "Community_Cloud") let url = URL(string: "https://status.salesforce.com/products/Community_Cloud")! } typealias Datorama = BaseDatorama & RequiredServiceProperties & SalesforceStoreService class BaseDatorama: BaseSalesforceCategory { static var store = SalesforceStore(key: "Datorama") let url = URL(string: "https://status.salesforce.com/products/Datorama")! } typealias Heroku = BaseHeroku & RequiredServiceProperties & SalesforceStoreService class BaseHeroku: BaseSalesforceCategory { static var store = SalesforceStore(key: "Heroku") let url = URL(string: "https://status.salesforce.com/products/Heroku")! } typealias MCAccountEngagement = BaseMCAccountEngagement & RequiredServiceProperties & SalesforceStoreService class BaseMCAccountEngagement: BaseSalesforceCategory { static var store = SalesforceStore(key: "MCAccountEngagement") let url = URL(string: "https://status.salesforce.com/products/MCAccountEngagement")! } typealias MCPersonalization = BaseMCPersonalization & RequiredServiceProperties & SalesforceStoreService class BaseMCPersonalization: BaseSalesforceCategory { static var store = SalesforceStore(key: "MCPersonalization") let url = URL(string: "https://status.salesforce.com/products/MCPersonalization")! } typealias SalesforceMarketingCloud = BaseSalesforceMarketingCloud & RequiredServiceProperties & SalesforceStoreService class BaseSalesforceMarketingCloud: BaseSalesforceCategory { static var store = SalesforceStore(key: "Marketing_Cloud") let url = URL(string: "https://status.salesforce.com/products/Marketing_Cloud")! } typealias Mulesoft = BaseMulesoft & RequiredServiceProperties & SalesforceStoreService class BaseMulesoft: BaseSalesforceCategory { static var store = SalesforceStore(key: "Mulesoft") let url = URL(string: "https://status.salesforce.com/products/Mulesoft")! } typealias SalesforceServices = BaseSalesforceServices & RequiredServiceProperties & SalesforceStoreService class BaseSalesforceServices: BaseSalesforceCategory { static var store = SalesforceStore(key: "Salesforce_Services") let url = URL(string: "https://status.salesforce.com/products/Salesforce_Services")! } typealias Spiff = BaseSpiff & RequiredServiceProperties & SalesforceStoreService class BaseSpiff: BaseSalesforceCategory { static var store = SalesforceStore(key: "Spiff") let url = URL(string: "https://status.salesforce.com/products/Spiff")! } typealias Tableau = BaseTableau & RequiredServiceProperties & SalesforceStoreService class BaseTableau: BaseSalesforceCategory { static var store = SalesforceStore(key: "Tableau") let url = URL(string: "https://status.salesforce.com/products/Tableau")! } ================================================ FILE: stts/Services/Super/SalesforceStore.swift ================================================ // // SalesforceStore.swift // SalesforceStore // import Foundation protocol SalesforceStoreService { var key: String { get } var location: String { get } } class SalesforceStore: ServiceStore<[String: ServiceStatus]> { let key: String private var url: URL { URL(string: "https://api.status.salesforce.com/v1/instances/status/preview?products=\(key)")! } init(key: String) { self.key = key } override func retrieveUpdatedState() async throws -> [String: ServiceStatus] { let instances = try await decoded([SalesforceResponseData.Instance].self, from: url) var serviceStatuses = [String: ServiceStatus]() instances.forEach { instance in var locationStatus = serviceStatuses[instance.location] ?? .undetermined locationStatus = [locationStatus, instance.status.serviceStatus].max() ?? .undetermined serviceStatuses[instance.location] = locationStatus var allLocationsStatus = serviceStatuses["*"] ?? .undetermined allLocationsStatus = [allLocationsStatus, instance.status.serviceStatus].max() ?? .undetermined serviceStatuses["*"] = allLocationsStatus } return serviceStatuses } func updatedStatus(for service: SalesforceStoreService) async throws -> ServiceStatusDescription { let updatedState = try await updatedState() let status = updatedState[service.location] ?? .undetermined let message: String switch status { case .good: message = "Available" case .minor: message = "Performance Degradation" case .major: message = "Service Disruption" case .maintenance: message = "Maintenance" case .notice: message = "Notice" case .undetermined: message = loadErrorMessage ?? "Unexpected error" } return ServiceStatusDescription(status: status, message: message) } } private struct SalesforceResponseData: Codable { struct Instance: Codable { enum CodingKeys: String, CodingKey { case location case status } let location: String let status: Status } enum Status: String, Codable { case ok = "OK" case maintenanceNonCore = "MAINTENANCE_NONCORE" case maintenanceCore = "MAINTENANCE_CORE" case minorNonCore = "MINOR_INCIDENT_NONCORE" case minorCore = "MINOR_INCIDENT_CORE" case majorNonCore = "MAJOR_INCIDENT_NONCORE" case majorCore = "MAJOR_INCIDENT_CORE" var serviceStatus: ServiceStatus { switch self { case .ok: return .good case .maintenanceNonCore, .maintenanceCore: return .maintenance case .minorNonCore, .minorCore, .majorNonCore: return .minor case .majorCore: return .major } } } } ================================================ FILE: stts/Services/Super/SendbirdService.swift ================================================ // // SendbirdService.swift // SendbirdService // import Foundation class SendbirdServiceDefinition: StatusPageServiceDefinition { override func build() -> BaseService? { SendbirdService(self) } } class SendbirdService: StatusPageService {} ================================================ FILE: stts/Services/Super/Service.swift ================================================ // // Service.swift // stts // import Foundation public enum ServiceStatus: Int, Comparable { case undetermined case good case notice case maintenance case minor case major public static func < (lhs: ServiceStatus, rhs: ServiceStatus) -> Bool { return lhs.rawValue < rhs.rawValue } } public struct ServiceStatusDescription { public let status: ServiceStatus public let message: ServiceStatusMessage } public typealias ServiceStatusMessage = String public extension ServiceStatusMessage { static func from(_ error: Error?) -> Self { if let statusUpdateError = error as? StatusUpdateError { switch statusUpdateError { case .networkError(let error): return "Network error: \(from(error))" case .parseError(let error): return "Parse error: \(from(error))" case .decodingError(let error): return "Decoding error: \(from(error))" case .custom(let string): return string } } else if (error as NSError?)?.code == NSURLErrorNotConnectedToInternet { return "Internet connection offline." } else { return error?.localizedDescription ?? "Unexpected error" } } } protocol ComparableStatus: Comparable { var serviceStatus: ServiceStatus { get } } extension ComparableStatus { public static func < (lhs: Self, rhs: Self) -> Bool { return lhs.serviceStatus < rhs.serviceStatus } } typealias Service = BaseService & RequiredServiceProperties protocol RequiredServiceProperties { var name: String { get } var url: URL { get } } extension RequiredServiceProperties { // Default implementation of the property `name` is to return the class name var name: String { return "\(type(of: self))" } } protocol ServiceCategory { /// The name of the category as it's displayed in the list var categoryName: String { get } /// The superclass of the sub services inside that category. var subServiceSuperclass: AnyObject.Type { get } } protocol SubService {} // Fits in a service submenu enum StatusUpdateError: Error { case networkError(Error) case parseError(Error?) case decodingError(Error?) case custom(String) } public class BaseService { @Atomic var statusDescription: ServiceStatusDescription = .init( status: .undetermined, message: "Loading…" ) var status: ServiceStatus { statusDescription.status } var message: ServiceStatusMessage { statusDescription.message } private var lastNotifiedStatus: ServiceStatus? public func updateStatus() async throws { fatalError("Override updateStatus() to support loading the status") } func notifyIfStatusChanged() { guard let realSelf = self as? Service else { fatalError("BaseService should not be used directly.") } let notifyBecauseDifferent = lastNotifiedStatus != nil && lastNotifiedStatus != .undetermined && status != .undetermined && lastNotifiedStatus != status if notifyBecauseDifferent { let notification = NSUserNotification() let possessiveS = realSelf.name.hasSuffix("s") ? "'" : "'s" notification.title = "\(realSelf.name)\(possessiveS) status has changed" notification.informativeText = message NSUserNotificationCenter.default.deliver(notification) } lastNotifiedStatus = status } } extension BaseService: Equatable { public static func == (lhs: BaseService, rhs: BaseService) -> Bool { guard let lhs = lhs as? Service, let rhs = rhs as? Service else { fatalError("BaseService should not be used directly.") } return lhs.name == rhs.name } } extension BaseService: Comparable { public static func < (lhs: BaseService, rhs: BaseService) -> Bool { guard let lhs = lhs as? Service, let rhs = rhs as? Service else { fatalError("BaseService should not be used directly.") } let sameStatus = lhs.status == rhs.status let differentStatus = lhs.status != .good && lhs.status != .notice && rhs.status == .good || rhs.status == .notice return (lhs.name.localizedCompare(rhs.name) == .orderedAscending && sameStatus) || differentStatus } } extension BaseService: Hashable { public func hash(into hasher: inout Hasher) { guard let service = self as? Service else { fatalError("BaseService should not be used directly.") } hasher.combine(service.name) } } extension BaseService: Loading {} extension BaseService { public func updateStatusAutomaticallyHandlingErrors() async { do { try await updateStatus() } catch { statusDescription = ServiceStatusDescription( status: .undetermined, message: ServiceStatusMessage.from(error) ) } } } ================================================ FILE: stts/Services/Super/ServiceStore.swift ================================================ // // ServiceStore.swift // stts // import Foundation protocol InitializableState { init() } extension Dictionary: InitializableState {} extension Array: InitializableState {} class ServiceStore: Loading { private var state: State private(set) var loadErrorMessage: String? @Atomic private var loadingTask: Task? init() { state = State() } func updatedState() async throws -> State { if loadingTask == nil { loadErrorMessage = nil loadingTask = createLoadingTask() } try await loadingTask?.value return state } func retrieveUpdatedState() async throws -> State { fatalError("retrieveUpdatedState is not implemented") } private func createLoadingTask() -> Task { Task { [weak self] in guard let self else { return } do { state = try await retrieveUpdatedState() } catch { loadErrorMessage = ServiceStatusMessage.from(error) throw error } // Set the task to nil after 5 seconds; This makes it so that calling updatedState() triggers the fetching // of new data. (This throttling is to prevent calls to multiple services' updateStatus() from fetching // new data again if the network call is too fast) Task { [weak self] in try await Task.sleep(seconds: 5) self?.resetTask() } } } private func resetTask() { loadingTask = nil } } ================================================ FILE: stts/Services/Super/Site24x7Service.swift ================================================ // // Site24x7Service.swift // stts // import Foundation class Site24x7ServiceDefinition: CodableServiceDefinition, ServiceDefinition { enum ExtraKeys: String, CodingKey { case id } // Can be found by searching for "enc_statuspage_id" in the status page HTML let id: String let providerIdentifier = "site24x7" required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: ExtraKeys.self) id = try container.decode(String.self, forKey: .id) try super.init(from: decoder) } override func encode(to encoder: Encoder) throws { try super.encode(to: encoder) var container = encoder.container(keyedBy: ExtraKeys.self) try container.encode(id, forKey: .id) } func build() -> BaseService? { Site24x7Service(self) } } private protocol RepresentableComponent { var displayName: String { get } var status: Site24x7Status { get } } private enum Site24x7Status: Int, Codable { case operational = 1 case informational = 2 case underMaintenance = 4 // 4 instead of 3 intentionally case degradedPerformance = 3 case partialOutage = 5 case majorOutage = 6 var displayName: String { switch self { case .operational: return "Operational" case .informational: return "Informational" case .underMaintenance: return "Under Maintenance" case .degradedPerformance: return "Degraded Performance" case .partialOutage: return "Partial Outage" case .majorOutage: return "Major Outage" } } var status: ServiceStatus { switch self { case .operational: return .good case .informational: return .notice case .underMaintenance: return .maintenance case .degradedPerformance, .partialOutage: return .minor case .majorOutage: return .major } } } class Site24x7Service: Service { private struct Response: Decodable { let data: ResponseData } private struct ResponseData: Decodable { enum CodingKeys: String, CodingKey { case currentStatus = "current_status" } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) var componentsArray = try container.nestedUnkeyedContainer(forKey: .currentStatus) var resultComponents = [RepresentableComponent]() while !componentsArray.isAtEnd { if let componentGroup = try? componentsArray.decode(ComponentGroup.self) { resultComponents.append(componentGroup) } else if let component = try? componentsArray.decode(Component.self) { resultComponents.append(component) } } if resultComponents.isEmpty { let context = DecodingError.Context( codingPath: [CodingKeys.currentStatus], debugDescription: "No components found in current_status" ) throw DecodingError.valueNotFound(ResponseData.self, context) } components = resultComponents } let components: [RepresentableComponent] } private struct ComponentGroup: Codable, RepresentableComponent { enum CodingKeys: String, CodingKey { case displayName = "componentgroup_display_name" case components = "componentgroup_components" case status = "componentgroup_status" } let displayName: String let components: [Component] let status: Site24x7Status } private struct Component: Codable, RepresentableComponent { enum CodingKeys: String, CodingKey { case displayName = "display_name" case status = "component_status" } let displayName: String let status: Site24x7Status } let id: String let name: String let url: URL init(_ definition: Site24x7ServiceDefinition) { id = definition.id name = definition.name url = definition.url } override func updateStatus() async throws { let apiURL = url .appendingPathComponent("sp/api/public/summary_details/statuspages") .appendingPathComponent(id) let response = try await decoded(Response.self, from: apiURL) guard !response.data.components.isEmpty else { throw StatusUpdateError.decodingError(nil) } let status = status(for: response.data.components) statusDescription = ServiceStatusDescription( status: status.status, message: statusMessage(for: status, components: response.data.components) ) } private func status(for components: [RepresentableComponent]) -> Site24x7Status { let flattenedComponents = components.flatMap { component -> [RepresentableComponent] in if let componentGroup = component as? ComponentGroup { return componentGroup.components } else { return [component] } } let worstComponent = flattenedComponents.max(by: { (one, two) -> Bool in one.status.status < two.status.status })! // We checked that it's not empty above return worstComponent.status } private func statusMessage(for status: Site24x7Status, components: [RepresentableComponent]) -> String { var message: [String] = [] message.append(status.displayName) for component in components { if let componentGroup = component as? ComponentGroup { var addedGroupName = false for subcomponent in componentGroup.components where subcomponent.status != .operational { if !addedGroupName { message.append("* \(componentGroup.displayName)") addedGroupName = true } message.append(" \(subcomponent.displayName)") } } else if component.status != .operational { message.append("* \(component.displayName)") } } return message.joined(separator: "\n") } } ================================================ FILE: stts/Services/Super/SorryService.swift ================================================ // // SorryService.swift // stts // import Foundation class SorryServiceDefinition: CodableServiceDefinition, ServiceDefinition { enum ExtraKeys: String, CodingKey { case id } let id: String let providerIdentifier = "sorry" required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: ExtraKeys.self) id = try container.decode(String.self, forKey: .id) try super.init(from: decoder) } override func encode(to encoder: Encoder) throws { try super.encode(to: encoder) var container = encoder.container(keyedBy: ExtraKeys.self) try container.encode(id, forKey: .id) } func build() -> BaseService? { SorryService(self) } } class SorryService: Service { private enum SorryStatus: String, ComparableStatus { case operational case degraded case partiallyDegraded = "partially-degraded" var description: String { switch self { case .operational: return "Operational" case .degraded: return "Degraded" case .partiallyDegraded: return "Partially Degraded" } } var serviceStatus: ServiceStatus { switch self { case .operational: return .good case .degraded: return .major case .partiallyDegraded: return .minor } } } let id: String let name: String let url: URL init(_ definition: SorryServiceDefinition) { id = definition.id name = definition.name url = definition.url } override func updateStatus() async throws { let statusURL = URL(string: "https://api.sorryapp.com/v1/pages/\(id)/components")! let data = try await rawData(from: statusURL) guard let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any], let components = json["response"] as? [[String: Any]] else { throw StatusUpdateError.decodingError(nil) } let statuses = components.compactMap { $0["state"] as? String }.compactMap(SorryStatus.init(rawValue:)) let worstStatus = statuses.max() statusDescription = ServiceStatusDescription( status: worstStatus?.serviceStatus ?? .undetermined, message: worstStatus?.description ?? "Unexpected response" ) } } ================================================ FILE: stts/Services/Super/StatusCakeService.swift ================================================ // // StatusCakeService.swift // stts // import Foundation class StatusCakeServiceDefinition: CodableServiceDefinition, ServiceDefinition { enum ExtraKeys: String, CodingKey { case id } let id: String let providerIdentifier = "statuscake" required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: ExtraKeys.self) id = try container.decode(String.self, forKey: .id) try super.init(from: decoder) } override func encode(to encoder: Encoder) throws { try super.encode(to: encoder) var container = encoder.container(keyedBy: ExtraKeys.self) try container.encode(id, forKey: .id) } func build() -> BaseService? { StatusCakeService(self) } } class StatusCakeService: Service { private enum StatusCakeStatus: String, ComparableStatus { case up = "Up" case down = "Down" var description: String { return rawValue } var serviceStatus: ServiceStatus { switch self { case .up: return .good case .down: return .major } } } let id: String let name: String let url: URL init(_ definition: StatusCakeServiceDefinition) { id = definition.id name = definition.name url = definition.url } override func updateStatus() async throws { let statusURL = URL( string: "https://app.statuscake.com/Workfloor/PublicReportHandler.php?PublicID=\(id)" )! let data = try await rawData(from: statusURL) guard let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any], let testData = json["TestData"] as? [[String: Any]] else { throw StatusUpdateError.decodingError(nil) } let statuses = testData.compactMap { $0["Status"] as? String }.compactMap(StatusCakeStatus.init(rawValue:)) let highestStatus = statuses.max() statusDescription = ServiceStatusDescription( status: highestStatus?.serviceStatus ?? .undetermined, message: highestStatus?.description ?? "Unexpected response" ) } } ================================================ FILE: stts/Services/Super/StatusCastService.swift ================================================ // // StatusCastService.swift // stts // import Foundation import Kanna class StatusCastServiceDefinition: CodableServiceDefinition, ServiceDefinition { let providerIdentifier = "statuscast" func build() -> BaseService? { StatusCastService(self) } } class StatusCastService: Service { private enum Status: String, CaseIterable { case available case unavailable case informational case monitored case identified case investigating case degraded case maintenance var serviceStatus: ServiceStatus { switch self { case .available: return .good case .unavailable: return .major case .informational, .monitored, .identified: return .notice case .investigating, .degraded: return .minor case .maintenance: return .maintenance } } } let name: String let url: URL init(_ definition: StatusCastServiceDefinition) { name = definition.name url = definition.url } override func updateStatus() async throws { let doc = try await html(from: url) let statuses: [(ServiceStatus, String?)] = doc.css(".status-list-component-status-text").map { element in for status in Status.allCases { if element.className?.contains("component-\(status.rawValue)") == true { return ( status.serviceStatus, element.innerHTML?.trimmingCharacters(in: .whitespacesAndNewlines) ) } } return (.undetermined, nil) } guard let worstStatus = statuses.max(by: { $0.0 < $1.0 }) else { throw StatusUpdateError.decodingError(nil) } statusDescription = ServiceStatusDescription( status: worstStatus.0, message: worstStatus.1 ?? "Unexpected response" ) } } ================================================ FILE: stts/Services/Super/StatusHubService.swift ================================================ // // StatusHubService.swift // stts // import Foundation class StatusHubServiceDefinition: CodableServiceDefinition, ServiceDefinition { let providerIdentifier = "statushub" func build() -> BaseService? { StatusHubService(self) } } class StatusHubService: Service { private struct StatusHubResponse: Codable { struct Counters: Codable { enum CodingKeys: String, CodingKey { case upCount = "count_status_1" case affectedCount = "count_status_2" case downCount = "count_status_3" } let upCount: Int let affectedCount: Int let downCount: Int } let counters: Counters } let name: String let url: URL init(_ definition: StatusHubServiceDefinition) { name = definition.name url = definition.url } override func updateStatus() async throws { let statusURL = url.appendingPathComponent("api/statuses") let response = try await decoded(StatusHubResponse.self, from: statusURL) updateStatus(from: response) } private func updateStatus(from response: StatusHubResponse) { var status: ServiceStatus = .undetermined var messageComponents: [String] = [] if response.counters.upCount > 0 { status = .good messageComponents.append("\(response.counters.upCount) up") } if response.counters.affectedCount > 0 { status = .minor messageComponents.append("\(response.counters.affectedCount) affected") } if response.counters.downCount > 0 { status = .major messageComponents.append("\(response.counters.downCount) down") } let prefix: String switch status { case .good: prefix = "Operating normally" // We don't need the extra "X up" message when all is good messageComponents = [] case .minor: prefix = "Performance issues" case .major: prefix = "Service disruption" default: prefix = "Unexpected response" } let message = [prefix, messageComponents.joined(separator: ", ")].joined(separator: "\n") statusDescription = ServiceStatusDescription(status: status, message: message) } } ================================================ FILE: stts/Services/Super/StatusPageService.swift ================================================ // // StatusPageService.swift // stts // import Foundation class StatusPageServiceDefinition: CodableServiceDefinition, ServiceDefinition { enum ExtraKeys: String, CodingKey { case id case host } let id: String let host: String? let providerIdentifier = "statuspage" required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: ExtraKeys.self) id = try container.decode(String.self, forKey: .id) host = try container.decodeIfPresent(String.self, forKey: .host) try super.init(from: decoder) } override func encode(to encoder: Encoder) throws { try super.encode(to: encoder) var container = encoder.container(keyedBy: ExtraKeys.self) try container.encode(id, forKey: .id) try container.encode(host, forKey: .host) } func build() -> BaseService? { StatusPageService(self) } } class StatusPageService: Service { struct Summary: Codable { let components: [Component] let incidents: [Incident] let status: Status var sortedComponents: [Component] { var rootPositions = [String: Int]() components.forEach { if $0.groupID == nil { // root element rootPositions[$0.id] = $0.position } } let rootPositionForComponent: (_ component: Component) -> Int = { if let groupID = $0.groupID { return rootPositions[groupID] ?? 0 } else { return rootPositions[$0.id] ?? 0 } } return components.sorted { (componentA: Component, componentB: Component) in let aSortingID = componentA.sortingID(withRootPosition: rootPositionForComponent(componentA)) let bSortingID = componentB.sortingID(withRootPosition: rootPositionForComponent(componentB)) return aSortingID.localizedCaseInsensitiveCompare(bSortingID) == .orderedAscending } } } struct Status: Codable { enum Indicator: String, Codable { case none case minor case critical case major case maintenance var serviceStatus: ServiceStatus { switch self { case .none: return .good case .minor: return .minor case .critical, .major: return .major case .maintenance: return .maintenance } } } let description: String let indicator: Indicator } struct Incident: Codable { enum IncidentStatus: String, Codable { case investigating case identified case monitoring case resolved case postmortem } let id: String let name: String let status: IncidentStatus var isUnresolved: Bool { switch status { case .investigating, .identified, .monitoring: return true case .resolved, .postmortem: return false } } } struct Component: Codable { enum CodingKeys: String, CodingKey { case id case groupID = "group_id" case isGroup = "group" case position case name case status } enum ComponentStatus: String, Codable { case operational case majorOutage = "major_outage" case degradedPerformance = "degraded_performance" case partialOutage = "partial_outage" case underMaintenance = "under_maintenance" var serviceStatus: ServiceStatus { switch self { case .operational: return .good case .majorOutage: return .major case .degradedPerformance: return .notice case .partialOutage: return .minor case .underMaintenance: return .maintenance } } } let id: String let isGroup: Bool let groupID: String? let position: Int let name: String let status: ComponentStatus func sortingID(withRootPosition rootPosition: Int) -> String { [ String(rootPosition), groupID ?? id, isGroup ? "0" : String(position), name ].joined(separator: "_") } } let id: String let name: String let url: URL let host: String init(_ definition: StatusPageServiceDefinition) { id = definition.id name = definition.name url = definition.url host = definition.host ?? "statuspage.io" } override func updateStatus() async throws { let summaryURL = URL(string: "https://\(id).\(host)/api/v2/summary.json")! let summary = try await decoded(Summary.self, from: summaryURL) updateStatus(from: summary) } private func updateStatus(from summary: Summary) { // Set the status let status = summary.status.indicator.serviceStatus // Set the message by combining the unresolved incident names let unresolvedIncidents = summary.incidents.filter { $0.isUnresolved } if !unresolvedIncidents.isEmpty { let prefix = unresolvedIncidents.count > 1 ? "* " : "" let message = unresolvedIncidents.map { "\(prefix)\($0.name)" }.joined(separator: "\n") statusDescription = ServiceStatusDescription(status: status, message: message) return } // Or from the affected component names let affectedComponents = summary.sortedComponents.filter { $0.status != .operational } if !affectedComponents.isEmpty { let prefix = affectedComponents.count > 1 ? "* " : "" let message = affectedComponents .map { "\(prefix)\($0.name)" } .joined(separator: "\n") statusDescription = ServiceStatusDescription(status: status, message: message) return } // Fallback to the status description statusDescription = ServiceStatusDescription(status: status, message: summary.status.description) } } ================================================ FILE: stts/Services/Super/StatusioV1Service.swift ================================================ // // StatusioV1Service.swift // stts // import Foundation class StatusioV1ServiceDefinition: CodableServiceDefinition, ServiceDefinition { enum ExtraKeys: String, CodingKey { case id } let id: String let providerIdentifier = "statusiov1" required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: ExtraKeys.self) id = try container.decode(String.self, forKey: .id) try super.init(from: decoder) } override func encode(to encoder: Encoder) throws { try super.encode(to: encoder) var container = encoder.container(keyedBy: ExtraKeys.self) try container.encode(id, forKey: .id) } func build() -> BaseService? { StatusioV1Service(self) } } class StatusioV1Service: Service { private enum StatusioV1Status: Int { case operational = 100 case plannedMaintenance = 200 case degradedPerformance = 300 case partialServiceDisruption = 400 case serviceDisruption = 500 case securityEvent = 600 var serviceStatus: ServiceStatus { switch self { case .operational: return .good case .plannedMaintenance: return .maintenance case .degradedPerformance: return .minor case .partialServiceDisruption: return .minor case .serviceDisruption, .securityEvent: return .major } } } let id: String let name: String let url: URL init(_ definition: StatusioV1ServiceDefinition) { id = definition.id name = definition.name url = definition.url } override func updateStatus() async throws { let statusURL = URL(string: "https://api.status.io/1.0/status/\(id)")! let data = try await rawData(from: statusURL) guard let dict = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any], let resultJSON = dict["result"] as? [String: Any], let statusOverallJSON = resultJSON["status_overall"] as? [String: Any], let statusCode = statusOverallJSON["status_code"] as? Int, let status = StatusioV1Status(rawValue: statusCode), let statusMessage = statusOverallJSON["status"] as? String else { throw StatusUpdateError.decodingError(nil) } statusDescription = ServiceStatusDescription( status: status.serviceStatus, message: statusMessage ) } } ================================================ FILE: stts/Services/Super/StatuspalService.swift ================================================ // // StatuspalService.swift // stts // import Foundation import Kanna class StatuspalServiceDefinition: CodableServiceDefinition, ServiceDefinition { let providerIdentifier = "statuspal" func build() -> BaseService? { StatuspalService(self) } } class StatuspalService: Service { private enum Status: CaseIterable { case good case minor case major case scheduled var className: String { switch self { case .good: return "type-none" case .minor: return "type-minor" case .major: return "type-major" case .scheduled: return "type-scheduled" } } var serviceStatus: ServiceStatus { switch self { case .good: return .good case .minor: return .minor case .major: return .major case .scheduled: return .notice } } } let name: String let url: URL init(_ serviceDefinition: StatuspalServiceDefinition) { name = serviceDefinition.name url = serviceDefinition.url } override func updateStatus() async throws { let doc = try await html(from: url) let foundStatus: ServiceStatus if let className = doc.css(".system-status").first?.className { let matchedStatus = Status.allCases.first { status in className.lowercased().contains(status.className) } if let matchedStatus { foundStatus = matchedStatus.serviceStatus } else { foundStatus = .undetermined } } else { foundStatus = .undetermined } let message: String = doc.css(".system-status--description") .first? .text? .trimmingCharacters(in: .whitespacesAndNewlines) ?? "Unexpected response" statusDescription = ServiceStatusDescription(status: foundStatus, message: message) } } ================================================ FILE: stts/Services/Super/UptimeDotComService.swift ================================================ // // UptimeDotComService.swift // stts // import Foundation typealias UptimeDotComService = BaseUptimeDotComService & RequiredServiceProperties & RequiredUptimeDotComServices protocol RequiredUptimeDotComServices {} class BaseUptimeDotComService: BaseIndependentService { override func updateStatus() async throws { guard let realSelf = self as? UptimeDotComService else { fatalError("BaseUptimeDotComService should not be used directly.") } let raw = try await rawString(from: realSelf.url) if raw.range(of: "global_is_operational\": true") != nil { statusDescription = ServiceStatusDescription(status: .good, message: "All systems operational") } else if raw.range(of: "global_is_operational\": false") != nil { statusDescription = ServiceStatusDescription( status: .major, message: "Some systems are experiencing problems" ) } else { throw StatusUpdateError.parseError(nil) } } } ================================================ FILE: stts/Services/UptimeDotCom/JSDelivr.swift ================================================ // // JSDelivr.swift // stts // import Foundation class JSDelivr: UptimeDotComService { let name = "jsDelivr" let url = URL(string: "https://status.jsdelivr.com")! } ================================================ FILE: stts/Services/UptimeDotCom/Recurly.swift ================================================ // // Recurly.swift // stts // import Foundation class Recurly: UptimeDotComService { let url = URL(string: "https://status.recurly.com")! } ================================================ FILE: stts/Services/UptimeDotCom/UptimeDotCom.swift ================================================ // // UptimeDotCom.swift // stts // import Foundation class UptimeDotCom: UptimeDotComService { let name = "Uptime.com" let url = URL(string: "https://status.uptime.com")! } ================================================ FILE: stts/Services/Zendesk.swift ================================================ // // Zendesk.swift // stts // import Foundation private struct ZendeskIncidentsResponse: Codable { struct Incident: Codable { struct Attributes: Codable { let outage: Bool let resolvedAt: String? } let id: String let type: String let attributes: Attributes var status: ServiceStatus { if attributes.resolvedAt != nil { return .good } else if attributes.outage { return .major } else { return .minor } } } let data: [Incident] var globalStatus: ServiceStatus { data.map { $0.status }.max() ?? .undetermined } } class Zendesk: IndependentService { let url = URL(string: "https://status.zendesk.com")! override func updateStatus() async throws { let response = try await decoded( ZendeskIncidentsResponse.self, from: url.appendingPathComponent("api/ssp/incidents.json") ) let status = response.globalStatus let message: String switch status { case .good: message = "No incidents" case .major, .minor: message = "Active incidents" default: message = "Unexpected response" } statusDescription = ServiceStatusDescription(status: status, message: message) } } ================================================ FILE: stts/SwitchableTableViewController.swift ================================================ // // SwitchableTableViewController.swift // stts // import Cocoa protocol SwitchableTableViewController: AnyObject { var hidden: Bool { get set } func show() func hide() func willShow() func willHide() } extension SwitchableTableViewController { func show() { self.hidden = false self.willShow() } func hide() { self.hidden = true self.willHide() } } ================================================ FILE: stts/stts.entitlements ================================================ com.apple.security.app-sandbox com.apple.security.network.client ================================================ FILE: stts.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 2F65F490227A198400432E64 /* Recurly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F65F48F227A198400432E64 /* Recurly.swift */; }; 7C82768C2C8E3CA800C0E37B /* NSScreenExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C82768B2C8E3BE300C0E37B /* NSScreenExtensions.swift */; }; 91B0A21428197857007D8E8F /* StringExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91B0A21328197857007D8E8F /* StringExtensionsTests.swift */; }; B200CA74247FC5AE00DB0868 /* AdobeServices.swift in Sources */ = {isa = PBXBuildFile; fileRef = B200CA73247FC5AE00DB0868 /* AdobeServices.swift */; }; B200CA76247FC88700DB0868 /* Adobe.swift in Sources */ = {isa = PBXBuildFile; fileRef = B200CA75247FC88700DB0868 /* Adobe.swift */; }; B200CA78247FC8B700DB0868 /* AdobeStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B200CA77247FC8B700DB0868 /* AdobeStore.swift */; }; B205A9181D49D67700EA178D /* Service.swift in Sources */ = {isa = PBXBuildFile; fileRef = B205A9171D49D67700EA178D /* Service.swift */; }; B20883E52A59143E007578C8 /* MBPopup in Frameworks */ = {isa = PBXBuildFile; productRef = B20883E42A59143E007578C8 /* MBPopup */; }; B20883E82A59144F007578C8 /* Kanna in Frameworks */ = {isa = PBXBuildFile; productRef = B20883E72A59144F007578C8 /* Kanna */; }; B20883EB2A59146C007578C8 /* Reachability in Frameworks */ = {isa = PBXBuildFile; productRef = B20883EA2A59146C007578C8 /* Reachability */; }; B20883F32A59ADAE007578C8 /* StatusCastService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B20883F22A59ADAE007578C8 /* StatusCastService.swift */; }; B213A1771DC97E2B008E8E58 /* ServiceTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B213A1761DC97E2B008E8E58 /* ServiceTableViewController.swift */; }; B213A1791DC9EA25008E8E58 /* ServiceTableRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B213A1781DC9EA25008E8E58 /* ServiceTableRowView.swift */; }; B213D200269AFD45005EBDDA /* InstatusService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B213D1FF269AFD45005EBDDA /* InstatusService.swift */; }; B214B6062E7BC13A006B3B77 /* AppIcon.icon in Resources */ = {isa = PBXBuildFile; fileRef = B214B6052E7BC13A006B3B77 /* AppIcon.icon */; }; B2163AF820BA4E7500B14A85 /* sttsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2163AF720BA4E7500B14A85 /* sttsTests.swift */; }; B2163B0020BA56EF00B14A85 /* StatusCakeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2163AFF20BA56EF00B14A85 /* StatusCakeService.swift */; }; B2228B6226C9623C002F01F0 /* SendbirdAll.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2228B6126C9623C002F01F0 /* SendbirdAll.swift */; }; B2253A6B209F3C410039F574 /* GoogleStatusDashboardStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2253A6A209F3C410039F574 /* GoogleStatusDashboardStore.swift */; }; B2253A6D209F3F9F0039F574 /* FirebaseService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2253A6C209F3F9F0039F574 /* FirebaseService.swift */; }; B2253A6F209F42430039F574 /* Firebase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2253A6E209F42430039F574 /* Firebase.swift */; }; B225E3E01E44830F008E1D3D /* SwitchableTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B225E3DF1E44830F008E1D3D /* SwitchableTableViewController.swift */; }; B22602AF27D87D96001190F1 /* UptimeDotCom.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22602AE27D87D96001190F1 /* UptimeDotCom.swift */; }; B22602B127D881AF001190F1 /* OracleNetSuite.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22602B027D881AF001190F1 /* OracleNetSuite.swift */; }; B22602B327D88FA1001190F1 /* Zendesk.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22602B227D88FA1001190F1 /* Zendesk.swift */; }; B22651232B2EE1C1002F1CE2 /* PagerDutyService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22651222B2EE1C1002F1CE2 /* PagerDutyService.swift */; }; B22651252B2EE9FF002F1CE2 /* pagerduty-minor.html in Resources */ = {isa = PBXBuildFile; fileRef = B22651242B2EE9FF002F1CE2 /* pagerduty-minor.html */; }; B22651272B2EEA44002F1CE2 /* pagerduty-good.html in Resources */ = {isa = PBXBuildFile; fileRef = B22651262B2EEA44002F1CE2 /* pagerduty-good.html */; }; B22651292B2EEA52002F1CE2 /* PagerDutyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22651282B2EEA52002F1CE2 /* PagerDutyTests.swift */; }; B228DC0C2A7F520700D8DC5E /* BetterStackService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B228DC0B2A7F520700D8DC5E /* BetterStackService.swift */; }; B228DC132A7F86F900D8DC5E /* eyloo-major.html in Resources */ = {isa = PBXBuildFile; fileRef = B228DC112A7F86F900D8DC5E /* eyloo-major.html */; }; B228DC142A7F86F900D8DC5E /* buildjet-good.html in Resources */ = {isa = PBXBuildFile; fileRef = B228DC122A7F86F900D8DC5E /* buildjet-good.html */; }; B228DC162A7F872800D8DC5E /* BetterStackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B228DC152A7F872800D8DC5E /* BetterStackTests.swift */; }; B22B6B302F673895006528EB /* BundleServiceDefinitionProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22B6B292F673895006528EB /* BundleServiceDefinitionProvider.swift */; }; B22B6B312F673895006528EB /* ServiceDefinition.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22B6B2A2F673895006528EB /* ServiceDefinition.swift */; }; B22B6B322F673895006528EB /* UserDefinedServiceDefinitionProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22B6B2E2F673895006528EB /* UserDefinedServiceDefinitionProvider.swift */; }; B22B6B332F673895006528EB /* AppDefinedServiceDefinitionProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22B6B282F673895006528EB /* AppDefinedServiceDefinitionProvider.swift */; }; B22B6B342F673895006528EB /* ServicesStructure.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22B6B2D2F673895006528EB /* ServicesStructure.swift */; }; B22B6B352F673895006528EB /* ServiceLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22B6B2C2F673895006528EB /* ServiceLoader.swift */; }; B22B6B362F673895006528EB /* ServiceDefinitionProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22B6B2B2F673895006528EB /* ServiceDefinitionProvider.swift */; }; B22B6B382F6738A1006528EB /* TaskExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22B6B372F6738A1006528EB /* TaskExtensions.swift */; }; B22B6B3E2F6738B1006528EB /* Fastly.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22B6B392F6738B1006528EB /* Fastly.swift */; }; B22B6B422F6738CD006528EB /* SendbirdService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22B6B402F6738CD006528EB /* SendbirdService.swift */; }; B22B6B432F6738CD006528EB /* IndependentService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22B6B3F2F6738CD006528EB /* IndependentService.swift */; }; B22B6B442F6738CD006528EB /* ServiceStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22B6B412F6738CD006528EB /* ServiceStore.swift */; }; B22B6B492F673BDF006528EB /* SFSafeSymbols in Frameworks */ = {isa = PBXBuildFile; productRef = B22B6B482F673BDF006528EB /* SFSafeSymbols */; }; B22B6B4B2F673C39006528EB /* services.json in Resources */ = {isa = PBXBuildFile; fileRef = B22B6B4A2F673C39006528EB /* services.json */; }; B22B6B4D2F69040A006528EB /* mastodonsocial-major.html in Resources */ = {isa = PBXBuildFile; fileRef = B22B6B4C2F69040A006528EB /* mastodonsocial-major.html */; }; B22B6B4F2F69047D006528EB /* whereby-good.html in Resources */ = {isa = PBXBuildFile; fileRef = B22B6B4E2F69047D006528EB /* whereby-good.html */; }; B22FDE4821089C6200359EC9 /* PayPal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22FDE4721089C6200359EC9 /* PayPal.swift */; }; B22FDE4D2108A5AE00359EC9 /* PayPalProductProduction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22FDE4C2108A5AE00359EC9 /* PayPalProductProduction.swift */; }; B22FDE4F2108A5B700359EC9 /* PayPalProductSandbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22FDE4E2108A5B700359EC9 /* PayPalProductSandbox.swift */; }; B22FDE512108A5C200359EC9 /* PayPalAPIProduction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22FDE502108A5C200359EC9 /* PayPalAPIProduction.swift */; }; B22FDE532108A5CC00359EC9 /* PayPalAPISandbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = B22FDE522108A5CC00359EC9 /* PayPalAPISandbox.swift */; }; B23038F11E0DF3CC00B29095 /* Beanstalk.swift in Sources */ = {isa = PBXBuildFile; fileRef = B23038F01E0DF3CC00B29095 /* Beanstalk.swift */; }; B230CE7F21B95C5500E2005D /* Stripe.swift in Sources */ = {isa = PBXBuildFile; fileRef = B230CE7E21B95C5500E2005D /* Stripe.swift */; }; B242AB3626E34DE9007EE672 /* SignalWire.swift in Sources */ = {isa = PBXBuildFile; fileRef = B242AB3526E34DE9007EE672 /* SignalWire.swift */; }; B2430807210810D0003F8D07 /* Algolia.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2430806210810D0003F8D07 /* Algolia.swift */; }; B2493F061E2603F300556A83 /* GoogleCloudPlatform.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2493F051E2603F300556A83 /* GoogleCloudPlatform.swift */; }; B24D19F61DD072840052E539 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = B24D19F51DD072840052E539 /* Preferences.swift */; }; B24EE10026C8BF9500F7CE8B /* SalesforceProducts.swift in Sources */ = {isa = PBXBuildFile; fileRef = B24EE0FF26C8BF9500F7CE8B /* SalesforceProducts.swift */; }; B24EE10226C8BFD500F7CE8B /* Salesforce.swift in Sources */ = {isa = PBXBuildFile; fileRef = B24EE10126C8BFD500F7CE8B /* Salesforce.swift */; }; B24EE10426C8C07100F7CE8B /* SalesforceCategories.swift in Sources */ = {isa = PBXBuildFile; fileRef = B24EE10326C8C07100F7CE8B /* SalesforceCategories.swift */; }; B24EE10626C8C08A00F7CE8B /* SalesforceStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B24EE10526C8C08A00F7CE8B /* SalesforceStore.swift */; }; B254098D28FE71990009F956 /* BetterUptimeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B254098C28FE71990009F956 /* BetterUptimeService.swift */; }; B2542502293591610093AC83 /* StatusHubService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2542501293591610093AC83 /* StatusHubService.swift */; }; B2552F0429954C26003FF9EC /* ResponseOverridingURLSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2552F0329954C26003FF9EC /* ResponseOverridingURLSession.swift */; }; B2552F082995516B003FF9EC /* TestBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2552F072995516B003FF9EC /* TestBundle.swift */; }; B2563BBC22CBC3D500532C39 /* DataLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2563BBB22CBC3D500532C39 /* DataLoader.swift */; }; B2563BBE22CBC65A00532C39 /* ResponseSizeTrackingURLSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2563BBD22CBC65A00532C39 /* ResponseSizeTrackingURLSession.swift */; }; B256955C1E247C8C00FAE413 /* PagerDuty.swift in Sources */ = {isa = PBXBuildFile; fileRef = B25695531E247C8C00FAE413 /* PagerDuty.swift */; }; B25FBFFD1DCAF2CE0099A388 /* CustomScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B25FBFFC1DCAF2CE0099A388 /* CustomScrollView.swift */; }; B26EC1102F69101800DDD0B9 /* aiven-minor.html in Resources */ = {isa = PBXBuildFile; fileRef = B26EC10E2F69101800DDD0B9 /* aiven-minor.html */; }; B26EC1112F69101800DDD0B9 /* linear-good.html in Resources */ = {isa = PBXBuildFile; fileRef = B26EC10F2F69101800DDD0B9 /* linear-good.html */; }; B26EC1132F69101D00DDD0B9 /* IncidentIOTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B26EC1122F69101D00DDD0B9 /* IncidentIOTests.swift */; }; B276D7622C4132CA00974DB6 /* UptimeDotComService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B276D7612C4132CA00974DB6 /* UptimeDotComService.swift */; }; B276D7642C4134AB00974DB6 /* JSDelivr.swift in Sources */ = {isa = PBXBuildFile; fileRef = B276D7632C4134AB00974DB6 /* JSDelivr.swift */; }; B276D7682C414DE900974DB6 /* Broadcom.swift in Sources */ = {isa = PBXBuildFile; fileRef = B276D7672C414DE900974DB6 /* Broadcom.swift */; }; B276D76A2C41F93300974DB6 /* Okta.swift in Sources */ = {isa = PBXBuildFile; fileRef = B276D7692C41F93300974DB6 /* Okta.swift */; }; B276D76C2C42036A00974DB6 /* HeadlessHTMLRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B276D76B2C42036A00974DB6 /* HeadlessHTMLRenderer.swift */; }; B277BC9222B4BB5C000B55C3 /* AzureDevOps.swift in Sources */ = {isa = PBXBuildFile; fileRef = B277BC9122B4BB5C000B55C3 /* AzureDevOps.swift */; }; B277BC9422B4BB6D000B55C3 /* AzureDevOpsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B277BC9322B4BB6D000B55C3 /* AzureDevOpsStore.swift */; }; B277BC9822B4C16A000B55C3 /* AzureDevOpsServices.swift in Sources */ = {isa = PBXBuildFile; fileRef = B277BC9722B4C16A000B55C3 /* AzureDevOpsServices.swift */; }; B27F66A62A3609E8008DAF33 /* AWSService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B27F66A52A3609E8008DAF33 /* AWSService.swift */; }; B27F66A82A360DFF008DAF33 /* AWSStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B27F66A72A360DFF008DAF33 /* AWSStore.swift */; }; B27F66AA2A3621F7008DAF33 /* AWSServices.swift in Sources */ = {isa = PBXBuildFile; fileRef = B27F66A92A3621F7008DAF33 /* AWSServices.swift */; }; B2841CEB20BA6207004AFDB7 /* SorryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2841CEA20BA6207004AFDB7 /* SorryService.swift */; }; B2898FD01DC7441D0005F58F /* StatusIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2898FCF1DC7441D0005F58F /* StatusIndicator.swift */; }; B28E9128248250220026BAAA /* AppleServices.swift in Sources */ = {isa = PBXBuildFile; fileRef = B28E9127248250220026BAAA /* AppleServices.swift */; }; B28E912A248250F40026BAAA /* AppleStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B28E9129248250F40026BAAA /* AppleStore.swift */; }; B28E912C248255A40026BAAA /* AppleDeveloper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B28E912B248255A40026BAAA /* AppleDeveloper.swift */; }; B290315C1E4B0CA7005B58CC /* Evernote.swift in Sources */ = {isa = PBXBuildFile; fileRef = B290315B1E4B0CA7005B58CC /* Evernote.swift */; }; B2A0635E1E1341C900EEA762 /* StatusioV1Service.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2A0635D1E1341C900EEA762 /* StatusioV1Service.swift */; }; B2A23E341DD192CD0051E913 /* EditorTableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2A23E331DD192CD0051E913 /* EditorTableCell.swift */; }; B2A4A8161DC82CE300037E99 /* BottomBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2A4A8151DC82CE300037E99 /* BottomBar.swift */; }; B2A4D7E7247E72B50089EA77 /* AzureAll.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2A4D7E6247E72B50089EA77 /* AzureAll.swift */; }; B2A4D7E9247E73BC0089EA77 /* AzureDevOpsAll.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2A4D7E8247E73BC0089EA77 /* AzureDevOpsAll.swift */; }; B2A7EFED2A14537B0013C7AE /* CStateService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2A7EFEC2A14537B0013C7AE /* CStateService.swift */; }; B2A9BFB41DC6E30F001BD4B7 /* Icons.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2A9BFB31DC6E30F001BD4B7 /* Icons.swift */; }; B2AF06AB2A7AB42100448D1E /* StatuspalService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2AF06AA2A7AB42100448D1E /* StatuspalService.swift */; }; B2B015C21DBDE69B00699211 /* StatusTableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2B015C11DBDE69B00699211 /* StatusTableCell.swift */; }; B2B2D1031D49D5080014D780 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2B2D1021D49D5080014D780 /* AppDelegate.swift */; }; B2B2D1051D49D5080014D780 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B2B2D1041D49D5080014D780 /* Assets.xcassets */; }; B2B2D1081D49D5080014D780 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = B2B2D1061D49D5080014D780 /* MainMenu.xib */; }; B2B77AA927FBC729009B9C2A /* FirebaseStatusDashboardStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2B77AA827FBC729009B9C2A /* FirebaseStatusDashboardStore.swift */; }; B2BB19BA20B8FEFD00A97A87 /* CachetService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2BB19B920B8FEFD00A97A87 /* CachetService.swift */; }; B2C6703C2F69B6BE0043DC7A /* openai-major.html in Resources */ = {isa = PBXBuildFile; fileRef = B2C6703A2F69B6BE0043DC7A /* openai-major.html */; }; B2C6703E2F69B6BE0043DC7A /* rollbar-good.html in Resources */ = {isa = PBXBuildFile; fileRef = B2C6703B2F69B6BE0043DC7A /* rollbar-good.html */; }; B2C670402F69B9160043DC7A /* MiroAll.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2C6703F2F69B9160043DC7A /* MiroAll.swift */; }; B2C670422F69BB070043DC7A /* MiroService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2C670412F69BB030043DC7A /* MiroService.swift */; }; B2C670442F69BDA20043DC7A /* MiroTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2C670432F69BDA20043DC7A /* MiroTests.swift */; }; B2C670472F69BDA90043DC7A /* miro-good.html in Resources */ = {isa = PBXBuildFile; fileRef = B2C670452F69BDA90043DC7A /* miro-good.html */; }; B2C670482F69BDA90043DC7A /* miro-issue.html in Resources */ = {isa = PBXBuildFile; fileRef = B2C670462F69BDA90043DC7A /* miro-issue.html */; }; B2CEB9A11DFD8984005FB901 /* StartAtLogin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B2CEB9A01DFD8984005FB901 /* StartAtLogin.framework */; }; B2CEB9A21DFD8987005FB901 /* StartAtLogin.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = B2CEB9A01DFD8984005FB901 /* StartAtLogin.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; B2CEE5D722B49CB50073C743 /* Azure.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2CEE5D622B49CB50073C743 /* Azure.swift */; }; B2CEE5D922B49CC80073C743 /* AzureStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2CEE5D822B49CC80073C743 /* AzureStore.swift */; }; B2CEE5DB22B4A97B0073C743 /* AzureServices.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2CEE5DA22B4A97B0073C743 /* AzureServices.swift */; }; B2D006692A875AB5008B3A13 /* PreferencesWindow.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B2D006632A875AB5008B3A13 /* PreferencesWindow.framework */; }; B2D0066A2A875AB5008B3A13 /* PreferencesWindow.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = B2D006632A875AB5008B3A13 /* PreferencesWindow.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; B2D0066F2A875AC1008B3A13 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2D0066E2A875AC1008B3A13 /* PreferencesWindowController.swift */; }; B2D006742A875B06008B3A13 /* PreferencesSidebarMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2D006732A875B06008B3A13 /* PreferencesSidebarMenu.swift */; }; B2D006802A875C9D008B3A13 /* SFSafeSymbols in Frameworks */ = {isa = PBXBuildFile; productRef = B2D0067F2A875C9D008B3A13 /* SFSafeSymbols */; }; B2D006812A875AC1008B3A13 /* PreferencesAboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2D006802A875AC1008B3A13 /* PreferencesAboutView.swift */; }; B2D655E729B802ED00DBE417 /* InstatusTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2D655E629B802ED00DBE417 /* InstatusTests.swift */; }; B2D655EE29B807BF00DBE417 /* Site24x7Service.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2D655ED29B807BF00DBE417 /* Site24x7Service.swift */; }; B2DCE68D221591F2001447D8 /* LambStatusService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2DCE68C221591F2001447D8 /* LambStatusService.swift */; }; B2DCE6902215992E001447D8 /* Apple.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2DCE68F2215992E001447D8 /* Apple.swift */; }; B2DCE6952215ACDE001447D8 /* StringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2DCE6942215ACDE001447D8 /* StringExtensions.swift */; }; B2DEE0BE1E696D64006B198E /* Slack.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2DEE0BD1E696D64006B198E /* Slack.swift */; }; B2E018FD214E60E700C5F75B /* AppearanceObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2E018FC214E60E700C5F75B /* AppearanceObserver.swift */; }; B2E5DB362F6FBE7800D71269 /* NSAppearance+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2E5DB352F6FBE7800D71269 /* NSAppearance+Extensions.swift */; }; B2E70FD822B069BA000BCAD2 /* GoogleCloudPlatformServices.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2E70FD722B069BA000BCAD2 /* GoogleCloudPlatformServices.swift */; }; B2E70FDB22B07DBC000BCAD2 /* GoogleCloudPlatformAll.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2E70FDA22B07DBC000BCAD2 /* GoogleCloudPlatformAll.swift */; }; B2E70FDD22B07FB0000BCAD2 /* FirebaseServices.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2E70FDC22B07FB0000BCAD2 /* FirebaseServices.swift */; }; B2E832EC29DE4F5E000FA1BE /* AdobeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2E832EB29DE4F5E000FA1BE /* AdobeTests.swift */; }; B2E832EE29DE5104000FA1BE /* adobe-analytics-minor.json in Resources */ = {isa = PBXBuildFile; fileRef = B2E832ED29DE5104000FA1BE /* adobe-analytics-minor.json */; }; B2E8C0232A7A9203000239F0 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2E8C0222A7A9203000239F0 /* Atomic.swift */; }; B2EB51CE1E7004A3001D6F78 /* ExanaService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2EB51CD1E7004A3001D6F78 /* ExanaService.swift */; }; B2F55EE92408AB1A003D674C /* PlayStationNetwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2F55EE82408AB1A003D674C /* PlayStationNetwork.swift */; }; B2F55EEC2408B5F1003D674C /* PSNAmerica.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2F55EEB2408B5F1003D674C /* PSNAmerica.swift */; }; B2F55EEE2408B68F003D674C /* PSNAsia.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2F55EED2408B68F003D674C /* PSNAsia.swift */; }; B2F55EF02408B6A2003D674C /* PSNEurope.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2F55EEF2408B6A2003D674C /* PSNEurope.swift */; }; B2FBDF5F2A35D82000734667 /* IncidentIOService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2FBDF5E2A35D82000734667 /* IncidentIOService.swift */; }; B2FC3E732A87659800A9E641 /* PreferencesWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2FC3E722A87659800A9E641 /* PreferencesWindow.swift */; }; B2FC3E762A8766DB00A9E641 /* PreferencesServicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2FC3E752A8766DB00A9E641 /* PreferencesServicesView.swift */; }; B2FC3E782A926C2400A9E641 /* PreferencesGeneralView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2FC3E772A926C2400A9E641 /* PreferencesGeneralView.swift */; }; B2FDC91C1D67062200F0B728 /* StatusPageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2FDC91B1D67062200F0B728 /* StatusPageService.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ B2163AFA20BA4E7500B14A85 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = B2B2D0F71D49D5080014D780 /* Project object */; proxyType = 1; remoteGlobalIDString = B2B2D0FE1D49D5080014D780; remoteInfo = stts; }; B2D006672A875AB5008B3A13 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = B2B2D0F71D49D5080014D780 /* Project object */; proxyType = 1; remoteGlobalIDString = B2D006622A875AB5008B3A13; remoteInfo = PreferencesWindow; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ B22EC6891D80111900ED7917 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( B2CEB9A21DFD8987005FB901 /* StartAtLogin.framework in CopyFiles */, B2D0066A2A875AB5008B3A13 /* PreferencesWindow.framework in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 2F65F48F227A198400432E64 /* Recurly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Recurly.swift; sourceTree = ""; }; 7C82768B2C8E3BE300C0E37B /* NSScreenExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSScreenExtensions.swift; sourceTree = ""; }; 91B0A21328197857007D8E8F /* StringExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtensionsTests.swift; sourceTree = ""; }; B200CA71247FBC0A00DB0868 /* generate_adobe_services.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = generate_adobe_services.swift; sourceTree = ""; }; B200CA73247FC5AE00DB0868 /* AdobeServices.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdobeServices.swift; sourceTree = ""; }; B200CA75247FC88700DB0868 /* Adobe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Adobe.swift; sourceTree = ""; }; B200CA77247FC8B700DB0868 /* AdobeStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdobeStore.swift; sourceTree = ""; }; B205A9171D49D67700EA178D /* Service.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Service.swift; sourceTree = ""; }; B20883F22A59ADAE007578C8 /* StatusCastService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusCastService.swift; sourceTree = ""; }; B213A1761DC97E2B008E8E58 /* ServiceTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceTableViewController.swift; sourceTree = ""; }; B213A1781DC9EA25008E8E58 /* ServiceTableRowView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceTableRowView.swift; sourceTree = ""; }; B213D1FF269AFD45005EBDDA /* InstatusService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstatusService.swift; sourceTree = ""; }; B214B6052E7BC13A006B3B77 /* AppIcon.icon */ = {isa = PBXFileReference; lastKnownFileType = folder.iconcomposer.icon; path = AppIcon.icon; sourceTree = ""; }; B2163AF520BA4E7500B14A85 /* sttsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = sttsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; B2163AF720BA4E7500B14A85 /* sttsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = sttsTests.swift; sourceTree = ""; }; B2163AF920BA4E7500B14A85 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; B2163AFF20BA56EF00B14A85 /* StatusCakeService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusCakeService.swift; sourceTree = ""; }; B2228B6126C9623C002F01F0 /* SendbirdAll.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendbirdAll.swift; sourceTree = ""; }; B2253A6A209F3C410039F574 /* GoogleStatusDashboardStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GoogleStatusDashboardStore.swift; sourceTree = ""; }; B2253A6C209F3F9F0039F574 /* FirebaseService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseService.swift; sourceTree = ""; }; B2253A6E209F42430039F574 /* Firebase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Firebase.swift; sourceTree = ""; }; B225E3DF1E44830F008E1D3D /* SwitchableTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwitchableTableViewController.swift; sourceTree = ""; }; B22602AE27D87D96001190F1 /* UptimeDotCom.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UptimeDotCom.swift; sourceTree = ""; }; B22602B027D881AF001190F1 /* OracleNetSuite.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OracleNetSuite.swift; sourceTree = ""; }; B22602B227D88FA1001190F1 /* Zendesk.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Zendesk.swift; sourceTree = ""; }; B22651222B2EE1C1002F1CE2 /* PagerDutyService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PagerDutyService.swift; sourceTree = ""; }; B22651242B2EE9FF002F1CE2 /* pagerduty-minor.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "pagerduty-minor.html"; sourceTree = ""; }; B22651262B2EEA44002F1CE2 /* pagerduty-good.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "pagerduty-good.html"; sourceTree = ""; }; B22651282B2EEA52002F1CE2 /* PagerDutyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PagerDutyTests.swift; sourceTree = ""; }; B228DC0B2A7F520700D8DC5E /* BetterStackService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetterStackService.swift; sourceTree = ""; }; B228DC112A7F86F900D8DC5E /* eyloo-major.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "eyloo-major.html"; sourceTree = ""; }; B228DC122A7F86F900D8DC5E /* buildjet-good.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "buildjet-good.html"; sourceTree = ""; }; B228DC152A7F872800D8DC5E /* BetterStackTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetterStackTests.swift; sourceTree = ""; }; B22B6B282F673895006528EB /* AppDefinedServiceDefinitionProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDefinedServiceDefinitionProvider.swift; sourceTree = ""; }; B22B6B292F673895006528EB /* BundleServiceDefinitionProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleServiceDefinitionProvider.swift; sourceTree = ""; }; B22B6B2A2F673895006528EB /* ServiceDefinition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceDefinition.swift; sourceTree = ""; }; B22B6B2B2F673895006528EB /* ServiceDefinitionProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceDefinitionProvider.swift; sourceTree = ""; }; B22B6B2C2F673895006528EB /* ServiceLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceLoader.swift; sourceTree = ""; }; B22B6B2D2F673895006528EB /* ServicesStructure.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServicesStructure.swift; sourceTree = ""; }; B22B6B2E2F673895006528EB /* UserDefinedServiceDefinitionProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefinedServiceDefinitionProvider.swift; sourceTree = ""; }; B22B6B372F6738A1006528EB /* TaskExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskExtensions.swift; sourceTree = ""; }; B22B6B392F6738B1006528EB /* Fastly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Fastly.swift; sourceTree = ""; }; B22B6B3F2F6738CD006528EB /* IndependentService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IndependentService.swift; sourceTree = ""; }; B22B6B402F6738CD006528EB /* SendbirdService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendbirdService.swift; sourceTree = ""; }; B22B6B412F6738CD006528EB /* ServiceStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceStore.swift; sourceTree = ""; }; B22B6B4A2F673C39006528EB /* services.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = services.json; sourceTree = ""; }; B22B6B4C2F69040A006528EB /* mastodonsocial-major.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "mastodonsocial-major.html"; sourceTree = ""; }; B22B6B4E2F69047D006528EB /* whereby-good.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "whereby-good.html"; sourceTree = ""; }; B22FDE4721089C6200359EC9 /* PayPal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayPal.swift; sourceTree = ""; }; B22FDE4C2108A5AE00359EC9 /* PayPalProductProduction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayPalProductProduction.swift; sourceTree = ""; }; B22FDE4E2108A5B700359EC9 /* PayPalProductSandbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayPalProductSandbox.swift; sourceTree = ""; }; B22FDE502108A5C200359EC9 /* PayPalAPIProduction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayPalAPIProduction.swift; sourceTree = ""; }; B22FDE522108A5CC00359EC9 /* PayPalAPISandbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayPalAPISandbox.swift; sourceTree = ""; }; B23038F01E0DF3CC00B29095 /* Beanstalk.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Beanstalk.swift; sourceTree = ""; }; B230CE7E21B95C5500E2005D /* Stripe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stripe.swift; sourceTree = ""; }; B23E408B26A559350038DDF1 /* generate_salesforce_services.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = generate_salesforce_services.swift; sourceTree = ""; }; B242AB3526E34DE9007EE672 /* SignalWire.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalWire.swift; sourceTree = ""; }; B2430806210810D0003F8D07 /* Algolia.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Algolia.swift; sourceTree = ""; }; B2493F051E2603F300556A83 /* GoogleCloudPlatform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GoogleCloudPlatform.swift; sourceTree = ""; }; B24D19F51DD072840052E539 /* Preferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = ""; }; B24EE0FF26C8BF9500F7CE8B /* SalesforceProducts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SalesforceProducts.swift; sourceTree = ""; }; B24EE10126C8BFD500F7CE8B /* Salesforce.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Salesforce.swift; sourceTree = ""; }; B24EE10326C8C07100F7CE8B /* SalesforceCategories.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SalesforceCategories.swift; sourceTree = ""; }; B24EE10526C8C08A00F7CE8B /* SalesforceStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SalesforceStore.swift; sourceTree = ""; }; B254098C28FE71990009F956 /* BetterUptimeService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetterUptimeService.swift; sourceTree = ""; }; B2542501293591610093AC83 /* StatusHubService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusHubService.swift; sourceTree = ""; }; B2552F0329954C26003FF9EC /* ResponseOverridingURLSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResponseOverridingURLSession.swift; sourceTree = ""; }; B2552F072995516B003FF9EC /* TestBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestBundle.swift; sourceTree = ""; }; B2563BBB22CBC3D500532C39 /* DataLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataLoader.swift; sourceTree = ""; }; B2563BBD22CBC65A00532C39 /* ResponseSizeTrackingURLSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResponseSizeTrackingURLSession.swift; sourceTree = ""; }; B25695531E247C8C00FAE413 /* PagerDuty.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PagerDuty.swift; sourceTree = ""; }; B25FBFFC1DCAF2CE0099A388 /* CustomScrollView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomScrollView.swift; sourceTree = ""; }; B26EC10E2F69101800DDD0B9 /* aiven-minor.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "aiven-minor.html"; sourceTree = ""; }; B26EC10F2F69101800DDD0B9 /* linear-good.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "linear-good.html"; sourceTree = ""; }; B26EC1122F69101D00DDD0B9 /* IncidentIOTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncidentIOTests.swift; sourceTree = ""; }; B276D7612C4132CA00974DB6 /* UptimeDotComService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UptimeDotComService.swift; sourceTree = ""; }; B276D7632C4134AB00974DB6 /* JSDelivr.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSDelivr.swift; sourceTree = ""; }; B276D7672C414DE900974DB6 /* Broadcom.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Broadcom.swift; sourceTree = ""; }; B276D7692C41F93300974DB6 /* Okta.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Okta.swift; sourceTree = ""; }; B276D76B2C42036A00974DB6 /* HeadlessHTMLRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlessHTMLRenderer.swift; sourceTree = ""; }; B277BC9122B4BB5C000B55C3 /* AzureDevOps.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AzureDevOps.swift; sourceTree = ""; }; B277BC9322B4BB6D000B55C3 /* AzureDevOpsStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AzureDevOpsStore.swift; sourceTree = ""; }; B277BC9522B4BC6C000B55C3 /* generate_azure_devops_services.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = generate_azure_devops_services.swift; sourceTree = ""; }; B277BC9722B4C16A000B55C3 /* AzureDevOpsServices.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AzureDevOpsServices.swift; sourceTree = ""; }; B27F66A42A35EBAA008DAF33 /* generate_aws_services.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = generate_aws_services.swift; sourceTree = ""; }; B27F66A52A3609E8008DAF33 /* AWSService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AWSService.swift; sourceTree = ""; }; B27F66A72A360DFF008DAF33 /* AWSStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AWSStore.swift; sourceTree = ""; }; B27F66A92A3621F7008DAF33 /* AWSServices.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AWSServices.swift; sourceTree = ""; }; B2841CEA20BA6207004AFDB7 /* SorryService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SorryService.swift; sourceTree = ""; }; B2898FCF1DC7441D0005F58F /* StatusIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusIndicator.swift; sourceTree = ""; }; B28E912524824C3A0026BAAA /* generate_apple_services.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = generate_apple_services.swift; sourceTree = ""; }; B28E9127248250220026BAAA /* AppleServices.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppleServices.swift; sourceTree = ""; }; B28E9129248250F40026BAAA /* AppleStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleStore.swift; sourceTree = ""; }; B28E912B248255A40026BAAA /* AppleDeveloper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleDeveloper.swift; sourceTree = ""; }; B290315B1E4B0CA7005B58CC /* Evernote.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Evernote.swift; sourceTree = ""; }; B2A0635D1E1341C900EEA762 /* StatusioV1Service.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusioV1Service.swift; sourceTree = ""; }; B2A23E331DD192CD0051E913 /* EditorTableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditorTableCell.swift; sourceTree = ""; }; B2A4A8151DC82CE300037E99 /* BottomBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BottomBar.swift; sourceTree = ""; }; B2A4D7E6247E72B50089EA77 /* AzureAll.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AzureAll.swift; sourceTree = ""; }; B2A4D7E8247E73BC0089EA77 /* AzureDevOpsAll.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AzureDevOpsAll.swift; sourceTree = ""; }; B2A7EFEC2A14537B0013C7AE /* CStateService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CStateService.swift; sourceTree = ""; }; B2A9BFB31DC6E30F001BD4B7 /* Icons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Icons.swift; sourceTree = ""; }; B2AF06AA2A7AB42100448D1E /* StatuspalService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatuspalService.swift; sourceTree = ""; }; B2B015C11DBDE69B00699211 /* StatusTableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusTableCell.swift; sourceTree = ""; }; B2B2D0FF1D49D5080014D780 /* stts.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = stts.app; sourceTree = BUILT_PRODUCTS_DIR; }; B2B2D1021D49D5080014D780 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; B2B2D1041D49D5080014D780 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; B2B2D1071D49D5080014D780 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; B2B2D1091D49D5080014D780 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; B2B77AA827FBC729009B9C2A /* FirebaseStatusDashboardStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseStatusDashboardStore.swift; sourceTree = ""; }; B2BB19B920B8FEFD00A97A87 /* CachetService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CachetService.swift; sourceTree = ""; }; B2C6703A2F69B6BE0043DC7A /* openai-major.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "openai-major.html"; sourceTree = ""; }; B2C6703B2F69B6BE0043DC7A /* rollbar-good.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "rollbar-good.html"; sourceTree = ""; }; B2C6703F2F69B9160043DC7A /* MiroAll.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MiroAll.swift; sourceTree = ""; }; B2C670412F69BB030043DC7A /* MiroService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MiroService.swift; sourceTree = ""; }; B2C670432F69BDA20043DC7A /* MiroTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MiroTests.swift; sourceTree = ""; }; B2C670452F69BDA90043DC7A /* miro-good.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "miro-good.html"; sourceTree = ""; }; B2C670462F69BDA90043DC7A /* miro-issue.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "miro-issue.html"; sourceTree = ""; }; B2CEB9A01DFD8984005FB901 /* StartAtLogin.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StartAtLogin.framework; path = Carthage/Build/Mac/StartAtLogin.framework; sourceTree = SOURCE_ROOT; }; B2CEE5D622B49CB50073C743 /* Azure.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Azure.swift; sourceTree = ""; }; B2CEE5D822B49CC80073C743 /* AzureStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AzureStore.swift; sourceTree = ""; }; B2CEE5DA22B4A97B0073C743 /* AzureServices.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AzureServices.swift; sourceTree = ""; }; B2CEE5DC22B4A9900073C743 /* generate_azure_services.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = generate_azure_services.swift; sourceTree = ""; }; B2CF3FBF1DF7DD2100B66491 /* stts.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = stts.entitlements; sourceTree = ""; }; B2D006632A875AB5008B3A13 /* PreferencesWindow.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PreferencesWindow.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B2D0066E2A875AC1008B3A13 /* PreferencesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = ""; }; B2D006732A875B06008B3A13 /* PreferencesSidebarMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesSidebarMenu.swift; sourceTree = ""; }; B2D006802A875AC1008B3A13 /* PreferencesAboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesAboutView.swift; sourceTree = ""; }; B2D655E629B802ED00DBE417 /* InstatusTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstatusTests.swift; sourceTree = ""; }; B2D655ED29B807BF00DBE417 /* Site24x7Service.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Site24x7Service.swift; sourceTree = ""; }; B2DCE68C221591F2001447D8 /* LambStatusService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LambStatusService.swift; sourceTree = ""; }; B2DCE68F2215992E001447D8 /* Apple.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Apple.swift; sourceTree = ""; }; B2DCE6942215ACDE001447D8 /* StringExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtensions.swift; sourceTree = ""; }; B2DEE0BD1E696D64006B198E /* Slack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Slack.swift; sourceTree = ""; }; B2E018FC214E60E700C5F75B /* AppearanceObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceObserver.swift; sourceTree = ""; }; B2E5DB352F6FBE7800D71269 /* NSAppearance+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSAppearance+Extensions.swift"; sourceTree = ""; }; B2E70FD322B0657F000BCAD2 /* generate_services_plist.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = generate_services_plist.sh; sourceTree = ""; }; B2E70FD622B066EC000BCAD2 /* generate_google_services.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = generate_google_services.swift; sourceTree = ""; }; B2E70FD722B069BA000BCAD2 /* GoogleCloudPlatformServices.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoogleCloudPlatformServices.swift; sourceTree = ""; }; B2E70FDA22B07DBC000BCAD2 /* GoogleCloudPlatformAll.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GoogleCloudPlatformAll.swift; sourceTree = ""; }; B2E70FDC22B07FB0000BCAD2 /* FirebaseServices.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseServices.swift; sourceTree = ""; }; B2E832EB29DE4F5E000FA1BE /* AdobeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdobeTests.swift; sourceTree = ""; }; B2E832ED29DE5104000FA1BE /* adobe-analytics-minor.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "adobe-analytics-minor.json"; sourceTree = ""; }; B2E8C0222A7A9203000239F0 /* Atomic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = ""; }; B2EB51CD1E7004A3001D6F78 /* ExanaService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExanaService.swift; sourceTree = ""; }; B2F55EE82408AB1A003D674C /* PlayStationNetwork.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayStationNetwork.swift; sourceTree = ""; }; B2F55EEB2408B5F1003D674C /* PSNAmerica.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PSNAmerica.swift; sourceTree = ""; }; B2F55EED2408B68F003D674C /* PSNAsia.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PSNAsia.swift; sourceTree = ""; }; B2F55EEF2408B6A2003D674C /* PSNEurope.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PSNEurope.swift; sourceTree = ""; }; B2FBDF5E2A35D82000734667 /* IncidentIOService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncidentIOService.swift; sourceTree = ""; }; B2FC3E722A87659800A9E641 /* PreferencesWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindow.swift; sourceTree = ""; }; B2FC3E752A8766DB00A9E641 /* PreferencesServicesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesServicesView.swift; sourceTree = ""; }; B2FC3E772A926C2400A9E641 /* PreferencesGeneralView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesGeneralView.swift; sourceTree = ""; }; B2FDC91B1D67062200F0B728 /* StatusPageService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusPageService.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ B2163AF220BA4E7500B14A85 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; B2B2D0FC1D49D5080014D780 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( B22B6B492F673BDF006528EB /* SFSafeSymbols in Frameworks */, B20883E52A59143E007578C8 /* MBPopup in Frameworks */, B20883EB2A59146C007578C8 /* Reachability in Frameworks */, B20883E82A59144F007578C8 /* Kanna in Frameworks */, B2CEB9A11DFD8984005FB901 /* StartAtLogin.framework in Frameworks */, B2D006692A875AB5008B3A13 /* PreferencesWindow.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; B2D006602A875AB5008B3A13 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( B2D006802A875C9D008B3A13 /* SFSafeSymbols in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ B213A17A1DC9EA3F008E8E58 /* ServiceTableView */ = { isa = PBXGroup; children = ( B213A1781DC9EA25008E8E58 /* ServiceTableRowView.swift */, B213A1761DC97E2B008E8E58 /* ServiceTableViewController.swift */, B2898FCF1DC7441D0005F58F /* StatusIndicator.swift */, B2B015C11DBDE69B00699211 /* StatusTableCell.swift */, ); path = ServiceTableView; sourceTree = ""; }; B2163AF620BA4E7500B14A85 /* sttsTests */ = { isa = PBXGroup; children = ( B2552F0929955365003FF9EC /* Helpers */, B2563BC122CBC92400532C39 /* Mocks */, B2552EFC29954AE0003FF9EC /* Resources */, B2E832EB29DE4F5E000FA1BE /* AdobeTests.swift */, B228DC152A7F872800D8DC5E /* BetterStackTests.swift */, B26EC1122F69101D00DDD0B9 /* IncidentIOTests.swift */, B2163AF920BA4E7500B14A85 /* Info.plist */, B2D655E629B802ED00DBE417 /* InstatusTests.swift */, B2C670432F69BDA20043DC7A /* MiroTests.swift */, B22651282B2EEA52002F1CE2 /* PagerDutyTests.swift */, 91B0A21328197857007D8E8F /* StringExtensionsTests.swift */, B2163AF720BA4E7500B14A85 /* sttsTests.swift */, ); path = sttsTests; sourceTree = ""; }; B22651212B2EE19C002F1CE2 /* PagerDuty */ = { isa = PBXGroup; children = ( B25695531E247C8C00FAE413 /* PagerDuty.swift */, ); path = PagerDuty; sourceTree = ""; }; B22A9FFE2C0E142F0065CD30 /* UptimeDotCom */ = { isa = PBXGroup; children = ( B276D7632C4134AB00974DB6 /* JSDelivr.swift */, 2F65F48F227A198400432E64 /* Recurly.swift */, B22602AE27D87D96001190F1 /* UptimeDotCom.swift */, ); path = UptimeDotCom; sourceTree = ""; }; B22B6B2F2F673895006528EB /* ServiceLoader */ = { isa = PBXGroup; children = ( B22B6B282F673895006528EB /* AppDefinedServiceDefinitionProvider.swift */, B22B6B292F673895006528EB /* BundleServiceDefinitionProvider.swift */, B22B6B2A2F673895006528EB /* ServiceDefinition.swift */, B22B6B2B2F673895006528EB /* ServiceDefinitionProvider.swift */, B22B6B2C2F673895006528EB /* ServiceLoader.swift */, B22B6B2D2F673895006528EB /* ServicesStructure.swift */, B22B6B2E2F673895006528EB /* UserDefinedServiceDefinitionProvider.swift */, ); path = ServiceLoader; sourceTree = ""; }; B22FDE4921089D4F00359EC9 /* PayPal */ = { isa = PBXGroup; children = ( B22FDE502108A5C200359EC9 /* PayPalAPIProduction.swift */, B22FDE522108A5CC00359EC9 /* PayPalAPISandbox.swift */, B22FDE4C2108A5AE00359EC9 /* PayPalProductProduction.swift */, B22FDE4E2108A5B700359EC9 /* PayPalProductSandbox.swift */, ); path = PayPal; sourceTree = ""; }; B2552EFC29954AE0003FF9EC /* Resources */ = { isa = PBXGroup; children = ( B2E832ED29DE5104000FA1BE /* adobe-analytics-minor.json */, B26EC10E2F69101800DDD0B9 /* aiven-minor.html */, B228DC122A7F86F900D8DC5E /* buildjet-good.html */, B228DC112A7F86F900D8DC5E /* eyloo-major.html */, B26EC10F2F69101800DDD0B9 /* linear-good.html */, B22B6B4C2F69040A006528EB /* mastodonsocial-major.html */, B2C670452F69BDA90043DC7A /* miro-good.html */, B2C670462F69BDA90043DC7A /* miro-issue.html */, B2C6703A2F69B6BE0043DC7A /* openai-major.html */, B22651262B2EEA44002F1CE2 /* pagerduty-good.html */, B22651242B2EE9FF002F1CE2 /* pagerduty-minor.html */, B2C6703B2F69B6BE0043DC7A /* rollbar-good.html */, B22B6B4E2F69047D006528EB /* whereby-good.html */, ); path = Resources; sourceTree = ""; }; B2552F0929955365003FF9EC /* Helpers */ = { isa = PBXGroup; children = ( B2552F072995516B003FF9EC /* TestBundle.swift */, ); path = Helpers; sourceTree = ""; }; B2563BC122CBC92400532C39 /* Mocks */ = { isa = PBXGroup; children = ( B2552F0329954C26003FF9EC /* ResponseOverridingURLSession.swift */, B2563BBD22CBC65A00532C39 /* ResponseSizeTrackingURLSession.swift */, ); path = Mocks; sourceTree = ""; }; B274C6361DD56A9E00A6B350 /* EditorTableView */ = { isa = PBXGroup; children = ( B2A23E331DD192CD0051E913 /* EditorTableCell.swift */, ); path = EditorTableView; sourceTree = ""; }; B276C8E81DD473B50098B451 /* Frameworks */ = { isa = PBXGroup; children = ( B2CEB9A01DFD8984005FB901 /* StartAtLogin.framework */, ); name = Frameworks; path = Resources; sourceTree = ""; }; B2B2D0F61D49D5080014D780 = { isa = PBXGroup; children = ( B276C8E81DD473B50098B451 /* Frameworks */, B2B2D1001D49D5080014D780 /* Products */, B2FDC9211D67074900F0B728 /* Resources */, B2E70FD222B0650A000BCAD2 /* Scripts */, B2B2D1011D49D5080014D780 /* stts */, B2163AF620BA4E7500B14A85 /* sttsTests */, ); sourceTree = ""; }; B2B2D1001D49D5080014D780 /* Products */ = { isa = PBXGroup; children = ( B2B2D0FF1D49D5080014D780 /* stts.app */, B2163AF520BA4E7500B14A85 /* sttsTests.xctest */, B2D006632A875AB5008B3A13 /* PreferencesWindow.framework */, ); name = Products; sourceTree = ""; }; B2B2D1011D49D5080014D780 /* stts */ = { isa = PBXGroup; children = ( B274C6361DD56A9E00A6B350 /* EditorTableView */, B2DCE6932215ACD0001447D8 /* Extensions */, B2FC3E742A8766C900A9E641 /* Preferences */, B2D006642A875AB5008B3A13 /* PreferencesWindow */, B22B6B2F2F673895006528EB /* ServiceLoader */, B213A17A1DC9EA3F008E8E58 /* ServiceTableView */, B2FDC91F1D6706FB00F0B728 /* Services */, B2B2D1021D49D5080014D780 /* AppDelegate.swift */, B2E018FC214E60E700C5F75B /* AppearanceObserver.swift */, B2A4A8151DC82CE300037E99 /* BottomBar.swift */, B25FBFFC1DCAF2CE0099A388 /* CustomScrollView.swift */, B2563BBB22CBC3D500532C39 /* DataLoader.swift */, B276D76B2C42036A00974DB6 /* HeadlessHTMLRenderer.swift */, B2A9BFB31DC6E30F001BD4B7 /* Icons.swift */, B24D19F51DD072840052E539 /* Preferences.swift */, B225E3DF1E44830F008E1D3D /* SwitchableTableViewController.swift */, B2CF3FBF1DF7DD2100B66491 /* stts.entitlements */, ); path = stts; sourceTree = ""; }; B2D006642A875AB5008B3A13 /* PreferencesWindow */ = { isa = PBXGroup; children = ( B2E5DB352F6FBE7800D71269 /* NSAppearance+Extensions.swift */, B2D006802A875AC1008B3A13 /* PreferencesAboutView.swift */, B2D006732A875B06008B3A13 /* PreferencesSidebarMenu.swift */, B2D0066E2A875AC1008B3A13 /* PreferencesWindowController.swift */, ); path = PreferencesWindow; sourceTree = ""; }; B2DCE6932215ACD0001447D8 /* Extensions */ = { isa = PBXGroup; children = ( B2E8C0222A7A9203000239F0 /* Atomic.swift */, 7C82768B2C8E3BE300C0E37B /* NSScreenExtensions.swift */, B2DCE6942215ACDE001447D8 /* StringExtensions.swift */, B22B6B372F6738A1006528EB /* TaskExtensions.swift */, ); path = Extensions; sourceTree = ""; }; B2E70FD222B0650A000BCAD2 /* Scripts */ = { isa = PBXGroup; children = ( B200CA71247FBC0A00DB0868 /* generate_adobe_services.swift */, B28E912524824C3A0026BAAA /* generate_apple_services.swift */, B27F66A42A35EBAA008DAF33 /* generate_aws_services.swift */, B277BC9522B4BC6C000B55C3 /* generate_azure_devops_services.swift */, B2CEE5DC22B4A9900073C743 /* generate_azure_services.swift */, B2E70FD622B066EC000BCAD2 /* generate_google_services.swift */, B23E408B26A559350038DDF1 /* generate_salesforce_services.swift */, B2E70FD322B0657F000BCAD2 /* generate_services_plist.sh */, ); path = Scripts; sourceTree = ""; }; B2E70FDF22B0844F000BCAD2 /* Generated */ = { isa = PBXGroup; children = ( B27F66A92A3621F7008DAF33 /* AWSServices.swift */, B200CA73247FC5AE00DB0868 /* AdobeServices.swift */, B28E9127248250220026BAAA /* AppleServices.swift */, B277BC9722B4C16A000B55C3 /* AzureDevOpsServices.swift */, B2CEE5DA22B4A97B0073C743 /* AzureServices.swift */, B2E70FDC22B07FB0000BCAD2 /* FirebaseServices.swift */, B2E70FD722B069BA000BCAD2 /* GoogleCloudPlatformServices.swift */, B24EE0FF26C8BF9500F7CE8B /* SalesforceProducts.swift */, ); path = Generated; sourceTree = ""; }; B2F55EEA2408B562003D674C /* PlayStation Network */ = { isa = PBXGroup; children = ( B2F55EEB2408B5F1003D674C /* PSNAmerica.swift */, B2F55EED2408B68F003D674C /* PSNAsia.swift */, B2F55EEF2408B6A2003D674C /* PSNEurope.swift */, ); path = "PlayStation Network"; sourceTree = ""; }; B2FC3E742A8766C900A9E641 /* Preferences */ = { isa = PBXGroup; children = ( B2FC3E772A926C2400A9E641 /* PreferencesGeneralView.swift */, B2FC3E752A8766DB00A9E641 /* PreferencesServicesView.swift */, B2FC3E722A87659800A9E641 /* PreferencesWindow.swift */, ); path = Preferences; sourceTree = ""; }; B2FDC91F1D6706FB00F0B728 /* Services */ = { isa = PBXGroup; children = ( B2E70FDF22B0844F000BCAD2 /* Generated */, B22651212B2EE19C002F1CE2 /* PagerDuty */, B22FDE4921089D4F00359EC9 /* PayPal */, B2F55EEA2408B562003D674C /* PlayStation Network */, B2FDC9201D67071500F0B728 /* Super */, B22A9FFE2C0E142F0065CD30 /* UptimeDotCom */, B2430806210810D0003F8D07 /* Algolia.swift */, B2A4D7E6247E72B50089EA77 /* AzureAll.swift */, B2A4D7E8247E73BC0089EA77 /* AzureDevOpsAll.swift */, B23038F01E0DF3CC00B29095 /* Beanstalk.swift */, B276D7672C414DE900974DB6 /* Broadcom.swift */, B290315B1E4B0CA7005B58CC /* Evernote.swift */, B22B6B392F6738B1006528EB /* Fastly.swift */, B2253A6E209F42430039F574 /* Firebase.swift */, B2E70FDA22B07DBC000BCAD2 /* GoogleCloudPlatformAll.swift */, B2C6703F2F69B9160043DC7A /* MiroAll.swift */, B276D7692C41F93300974DB6 /* Okta.swift */, B22602B027D881AF001190F1 /* OracleNetSuite.swift */, B2228B6126C9623C002F01F0 /* SendbirdAll.swift */, B242AB3526E34DE9007EE672 /* SignalWire.swift */, B2DEE0BD1E696D64006B198E /* Slack.swift */, B230CE7E21B95C5500E2005D /* Stripe.swift */, B22602B227D88FA1001190F1 /* Zendesk.swift */, ); path = Services; sourceTree = ""; }; B2FDC9201D67071500F0B728 /* Super */ = { isa = PBXGroup; children = ( B27F66A52A3609E8008DAF33 /* AWSService.swift */, B27F66A72A360DFF008DAF33 /* AWSStore.swift */, B200CA75247FC88700DB0868 /* Adobe.swift */, B200CA77247FC8B700DB0868 /* AdobeStore.swift */, B2DCE68F2215992E001447D8 /* Apple.swift */, B28E912B248255A40026BAAA /* AppleDeveloper.swift */, B28E9129248250F40026BAAA /* AppleStore.swift */, B2CEE5D622B49CB50073C743 /* Azure.swift */, B277BC9122B4BB5C000B55C3 /* AzureDevOps.swift */, B277BC9322B4BB6D000B55C3 /* AzureDevOpsStore.swift */, B2CEE5D822B49CC80073C743 /* AzureStore.swift */, B228DC0B2A7F520700D8DC5E /* BetterStackService.swift */, B254098C28FE71990009F956 /* BetterUptimeService.swift */, B2A7EFEC2A14537B0013C7AE /* CStateService.swift */, B2BB19B920B8FEFD00A97A87 /* CachetService.swift */, B2EB51CD1E7004A3001D6F78 /* ExanaService.swift */, B2253A6C209F3F9F0039F574 /* FirebaseService.swift */, B2B77AA827FBC729009B9C2A /* FirebaseStatusDashboardStore.swift */, B2493F051E2603F300556A83 /* GoogleCloudPlatform.swift */, B2253A6A209F3C410039F574 /* GoogleStatusDashboardStore.swift */, B2FBDF5E2A35D82000734667 /* IncidentIOService.swift */, B22B6B3F2F6738CD006528EB /* IndependentService.swift */, B213D1FF269AFD45005EBDDA /* InstatusService.swift */, B2DCE68C221591F2001447D8 /* LambStatusService.swift */, B2C670412F69BB030043DC7A /* MiroService.swift */, B22651222B2EE1C1002F1CE2 /* PagerDutyService.swift */, B22FDE4721089C6200359EC9 /* PayPal.swift */, B2F55EE82408AB1A003D674C /* PlayStationNetwork.swift */, B24EE10126C8BFD500F7CE8B /* Salesforce.swift */, B24EE10326C8C07100F7CE8B /* SalesforceCategories.swift */, B24EE10526C8C08A00F7CE8B /* SalesforceStore.swift */, B22B6B402F6738CD006528EB /* SendbirdService.swift */, B205A9171D49D67700EA178D /* Service.swift */, B22B6B412F6738CD006528EB /* ServiceStore.swift */, B2D655ED29B807BF00DBE417 /* Site24x7Service.swift */, B2841CEA20BA6207004AFDB7 /* SorryService.swift */, B2163AFF20BA56EF00B14A85 /* StatusCakeService.swift */, B20883F22A59ADAE007578C8 /* StatusCastService.swift */, B2542501293591610093AC83 /* StatusHubService.swift */, B2FDC91B1D67062200F0B728 /* StatusPageService.swift */, B2A0635D1E1341C900EEA762 /* StatusioV1Service.swift */, B2AF06AA2A7AB42100448D1E /* StatuspalService.swift */, B276D7612C4132CA00974DB6 /* UptimeDotComService.swift */, ); path = Super; sourceTree = ""; }; B2FDC9211D67074900F0B728 /* Resources */ = { isa = PBXGroup; children = ( B214B6052E7BC13A006B3B77 /* AppIcon.icon */, B2B2D1041D49D5080014D780 /* Assets.xcassets */, B2B2D1091D49D5080014D780 /* Info.plist */, B2B2D1061D49D5080014D780 /* MainMenu.xib */, B22B6B4A2F673C39006528EB /* services.json */, ); path = Resources; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ B2D0065E2A875AB5008B3A13 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ B2163AF420BA4E7500B14A85 /* sttsTests */ = { isa = PBXNativeTarget; buildConfigurationList = B2163AFE20BA4E7500B14A85 /* Build configuration list for PBXNativeTarget "sttsTests" */; buildPhases = ( B2163AF120BA4E7500B14A85 /* Sources */, B2163AF220BA4E7500B14A85 /* Frameworks */, B2163AF320BA4E7500B14A85 /* Resources */, ); buildRules = ( ); dependencies = ( B2163AFB20BA4E7500B14A85 /* PBXTargetDependency */, ); name = sttsTests; productName = sttsTests; productReference = B2163AF520BA4E7500B14A85 /* sttsTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; B2B2D0FE1D49D5080014D780 /* stts */ = { isa = PBXNativeTarget; buildConfigurationList = B2B2D10C1D49D5080014D780 /* Build configuration list for PBXNativeTarget "stts" */; buildPhases = ( B242E7B422B08C8600A8EB40 /* Generate services */, B2B2D0FB1D49D5080014D780 /* Sources */, B2B2D0FC1D49D5080014D780 /* Frameworks */, B2B2D0FD1D49D5080014D780 /* Resources */, B22EC6891D80111900ED7917 /* CopyFiles */, B28F83321E24BDC100F2070F /* Generate Services plist file */, B2B2DC631DCC1FA600BF397D /* SwiftLint */, B2A264A21DF906C900009BE1 /* StartAtLogin */, ); buildRules = ( ); dependencies = ( B2D006682A875AB5008B3A13 /* PBXTargetDependency */, ); name = stts; packageProductDependencies = ( B20883E42A59143E007578C8 /* MBPopup */, B20883E72A59144F007578C8 /* Kanna */, B20883EA2A59146C007578C8 /* Reachability */, B22B6B482F673BDF006528EB /* SFSafeSymbols */, ); productName = stts; productReference = B2B2D0FF1D49D5080014D780 /* stts.app */; productType = "com.apple.product-type.application"; }; B2D006622A875AB5008B3A13 /* PreferencesWindow */ = { isa = PBXNativeTarget; buildConfigurationList = B2D0066B2A875AB5008B3A13 /* Build configuration list for PBXNativeTarget "PreferencesWindow" */; buildPhases = ( B2D0065E2A875AB5008B3A13 /* Headers */, B2D0065F2A875AB5008B3A13 /* Sources */, B2D006602A875AB5008B3A13 /* Frameworks */, B2D006612A875AB5008B3A13 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = PreferencesWindow; packageProductDependencies = ( B2D0067F2A875C9D008B3A13 /* SFSafeSymbols */, ); productName = PreferencesWindow; productReference = B2D006632A875AB5008B3A13 /* PreferencesWindow.framework */; productType = "com.apple.product-type.framework"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ B2B2D0F71D49D5080014D780 /* Project object */ = { isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 0930; LastUpgradeCheck = 2600; ORGANIZATIONNAME = inket; TargetAttributes = { B2163AF420BA4E7500B14A85 = { CreatedOnToolsVersion = 9.3.1; LastSwiftMigration = 1020; TestTargetID = B2B2D0FE1D49D5080014D780; }; B2B2D0FE1D49D5080014D780 = { CreatedOnToolsVersion = 8.0; DevelopmentTeamName = "Mahdi Bchatnia"; LastSwiftMigration = 1020; SystemCapabilities = { com.apple.Sandbox = { enabled = 1; }; }; }; B2D006622A875AB5008B3A13 = { CreatedOnToolsVersion = 1430; }; }; }; buildConfigurationList = B2B2D0FA1D49D5080014D780 /* Build configuration list for PBXProject "stts" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = B2B2D0F61D49D5080014D780; packageReferences = ( B20883E32A59143E007578C8 /* XCRemoteSwiftPackageReference "MBPopup" */, B20883E62A59144F007578C8 /* XCRemoteSwiftPackageReference "Kanna" */, B20883E92A59146C007578C8 /* XCRemoteSwiftPackageReference "Reachability.swift" */, B22B6B472F673BDF006528EB /* XCRemoteSwiftPackageReference "SFSafeSymbols" */, ); productRefGroup = B2B2D1001D49D5080014D780 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( B2B2D0FE1D49D5080014D780 /* stts */, B2163AF420BA4E7500B14A85 /* sttsTests */, B2D006622A875AB5008B3A13 /* PreferencesWindow */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ B2163AF320BA4E7500B14A85 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( B22651272B2EEA44002F1CE2 /* pagerduty-good.html in Resources */, B2E832EE29DE5104000FA1BE /* adobe-analytics-minor.json in Resources */, B22B6B4D2F69040A006528EB /* mastodonsocial-major.html in Resources */, B22B6B4F2F69047D006528EB /* whereby-good.html in Resources */, B26EC1102F69101800DDD0B9 /* aiven-minor.html in Resources */, B26EC1112F69101800DDD0B9 /* linear-good.html in Resources */, B228DC132A7F86F900D8DC5E /* eyloo-major.html in Resources */, B22651252B2EE9FF002F1CE2 /* pagerduty-minor.html in Resources */, B2C6703C2F69B6BE0043DC7A /* openai-major.html in Resources */, B2C670472F69BDA90043DC7A /* miro-good.html in Resources */, B2C670482F69BDA90043DC7A /* miro-issue.html in Resources */, B2C6703E2F69B6BE0043DC7A /* rollbar-good.html in Resources */, B228DC142A7F86F900D8DC5E /* buildjet-good.html in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; B2B2D0FD1D49D5080014D780 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( B2B2D1051D49D5080014D780 /* Assets.xcassets in Resources */, B22B6B4B2F673C39006528EB /* services.json in Resources */, B2B2D1081D49D5080014D780 /* MainMenu.xib in Resources */, B214B6062E7BC13A006B3B77 /* AppIcon.icon in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; B2D006612A875AB5008B3A13 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ B242E7B422B08C8600A8EB40 /* Generate services */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( ); name = "Generate services"; outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "chmod +x $SRCROOT/Scripts/*.swift\n\n$SRCROOT/Scripts/generate_adobe_services.swift &\n$SRCROOT/Scripts/generate_apple_services.swift &\n$SRCROOT/Scripts/generate_aws_services.swift &\n$SRCROOT/Scripts/generate_azure_services.swift &\n$SRCROOT/Scripts/generate_azure_devops_services.swift &\n$SRCROOT/Scripts/generate_google_services.swift &\n$SRCROOT/Scripts/generate_salesforce_services.swift\nwait\n"; }; B28F83321E24BDC100F2070F /* Generate Services plist file */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "Generate Services plist file"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "chmod +x $SRCROOT/Scripts/generate_services_plist.sh\n$SRCROOT/Scripts/generate_services_plist.sh\n"; }; B2A264A21DF906C900009BE1 /* StartAtLogin */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = StartAtLogin; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "FRAMEWORKS_HELPER_PATH=\"$BUILT_PRODUCTS_DIR/$FRAMEWORKS_FOLDER_PATH/StartAtLogin.framework/Versions/A/Resources/StartAtLoginHelper.app\"\nHELPER_DIR=\"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/LoginItems\"\nHELPER_PATH=\"$HELPER_DIR/StartAtLoginHelper.app\"\n\nmkdir -p \"$HELPER_DIR\"\nrm -rf \"$HELPER_PATH\"\ncp -rf \"$FRAMEWORKS_HELPER_PATH\" \"$HELPER_DIR/\"\n\nif [ \"$CONFIGURATION\" == \"Release\" ]; then\n rm -rf \"$FRAMEWORKS_HELPER_PATH\"\nfi\n\ndefaults write \"$HELPER_PATH/Contents/Info\" CFBundleIdentifier -string \"$PRODUCT_BUNDLE_IDENTIFIER-StartAtLoginHelper\"\ncodesign --force --entitlements \"$CODE_SIGN_ENTITLEMENTS\" -s \"$EXPANDED_CODE_SIGN_IDENTITY_NAME\" -v \"$HELPER_PATH\"\n"; }; B2B2DC631DCC1FA600BF397D /* SwiftLint */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = SwiftLint; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "export PATH=\"$PATH:/usr/local/bin/:/opt/homebrew/bin\"\nif which swiftlint >/dev/null; then\nswiftlint\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ B2163AF120BA4E7500B14A85 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 91B0A21428197857007D8E8F /* StringExtensionsTests.swift in Sources */, B2E832EC29DE4F5E000FA1BE /* AdobeTests.swift in Sources */, B2563BBE22CBC65A00532C39 /* ResponseSizeTrackingURLSession.swift in Sources */, B2552F082995516B003FF9EC /* TestBundle.swift in Sources */, B2C670442F69BDA20043DC7A /* MiroTests.swift in Sources */, B22651292B2EEA52002F1CE2 /* PagerDutyTests.swift in Sources */, B26EC1132F69101D00DDD0B9 /* IncidentIOTests.swift in Sources */, B228DC162A7F872800D8DC5E /* BetterStackTests.swift in Sources */, B2552F0429954C26003FF9EC /* ResponseOverridingURLSession.swift in Sources */, B2D655E729B802ED00DBE417 /* InstatusTests.swift in Sources */, B2163AF820BA4E7500B14A85 /* sttsTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; B2B2D0FB1D49D5080014D780 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( B2493F061E2603F300556A83 /* GoogleCloudPlatform.swift in Sources */, B24EE10226C8BFD500F7CE8B /* Salesforce.swift in Sources */, B2A4D7E7247E72B50089EA77 /* AzureAll.swift in Sources */, B2253A6B209F3C410039F574 /* GoogleStatusDashboardStore.swift in Sources */, B2E70FDD22B07FB0000BCAD2 /* FirebaseServices.swift in Sources */, B22602B327D88FA1001190F1 /* Zendesk.swift in Sources */, B28E9128248250220026BAAA /* AppleServices.swift in Sources */, B25FBFFD1DCAF2CE0099A388 /* CustomScrollView.swift in Sources */, B2A7EFED2A14537B0013C7AE /* CStateService.swift in Sources */, B24D19F61DD072840052E539 /* Preferences.swift in Sources */, B2BB19BA20B8FEFD00A97A87 /* CachetService.swift in Sources */, B22FDE4D2108A5AE00359EC9 /* PayPalProductProduction.swift in Sources */, B276D76C2C42036A00974DB6 /* HeadlessHTMLRenderer.swift in Sources */, B2B2D1031D49D5080014D780 /* AppDelegate.swift in Sources */, B2CEE5D722B49CB50073C743 /* Azure.swift in Sources */, B27F66A82A360DFF008DAF33 /* AWSStore.swift in Sources */, B2B015C21DBDE69B00699211 /* StatusTableCell.swift in Sources */, B276D76A2C41F93300974DB6 /* Okta.swift in Sources */, B2C670402F69B9160043DC7A /* MiroAll.swift in Sources */, B2CEE5DB22B4A97B0073C743 /* AzureServices.swift in Sources */, B2163B0020BA56EF00B14A85 /* StatusCakeService.swift in Sources */, B2CEE5D922B49CC80073C743 /* AzureStore.swift in Sources */, B213D200269AFD45005EBDDA /* InstatusService.swift in Sources */, B200CA76247FC88700DB0868 /* Adobe.swift in Sources */, B2898FD01DC7441D0005F58F /* StatusIndicator.swift in Sources */, B290315C1E4B0CA7005B58CC /* Evernote.swift in Sources */, B2253A6D209F3F9F0039F574 /* FirebaseService.swift in Sources */, B213A1771DC97E2B008E8E58 /* ServiceTableViewController.swift in Sources */, B2E70FDB22B07DBC000BCAD2 /* GoogleCloudPlatformAll.swift in Sources */, B2D655EE29B807BF00DBE417 /* Site24x7Service.swift in Sources */, B22B6B3E2F6738B1006528EB /* Fastly.swift in Sources */, B2DEE0BE1E696D64006B198E /* Slack.swift in Sources */, B276D7682C414DE900974DB6 /* Broadcom.swift in Sources */, B2AF06AB2A7AB42100448D1E /* StatuspalService.swift in Sources */, B2E70FD822B069BA000BCAD2 /* GoogleCloudPlatformServices.swift in Sources */, B276D7642C4134AB00974DB6 /* JSDelivr.swift in Sources */, 7C82768C2C8E3CA800C0E37B /* NSScreenExtensions.swift in Sources */, B2542502293591610093AC83 /* StatusHubService.swift in Sources */, B27F66A62A3609E8008DAF33 /* AWSService.swift in Sources */, B2A0635E1E1341C900EEA762 /* StatusioV1Service.swift in Sources */, B200CA78247FC8B700DB0868 /* AdobeStore.swift in Sources */, B277BC9822B4C16A000B55C3 /* AzureDevOpsServices.swift in Sources */, B2DCE6902215992E001447D8 /* Apple.swift in Sources */, B28E912C248255A40026BAAA /* AppleDeveloper.swift in Sources */, B24EE10426C8C07100F7CE8B /* SalesforceCategories.swift in Sources */, B2E018FD214E60E700C5F75B /* AppearanceObserver.swift in Sources */, B2228B6226C9623C002F01F0 /* SendbirdAll.swift in Sources */, B2FDC91C1D67062200F0B728 /* StatusPageService.swift in Sources */, B230CE7F21B95C5500E2005D /* Stripe.swift in Sources */, B2F55EE92408AB1A003D674C /* PlayStationNetwork.swift in Sources */, B2E8C0232A7A9203000239F0 /* Atomic.swift in Sources */, B2841CEB20BA6207004AFDB7 /* SorryService.swift in Sources */, B2A23E341DD192CD0051E913 /* EditorTableCell.swift in Sources */, B254098D28FE71990009F956 /* BetterUptimeService.swift in Sources */, B2C670422F69BB070043DC7A /* MiroService.swift in Sources */, B2430807210810D0003F8D07 /* Algolia.swift in Sources */, B22B6B302F673895006528EB /* BundleServiceDefinitionProvider.swift in Sources */, B22B6B312F673895006528EB /* ServiceDefinition.swift in Sources */, B22B6B322F673895006528EB /* UserDefinedServiceDefinitionProvider.swift in Sources */, B22B6B332F673895006528EB /* AppDefinedServiceDefinitionProvider.swift in Sources */, B22B6B342F673895006528EB /* ServicesStructure.swift in Sources */, B22B6B352F673895006528EB /* ServiceLoader.swift in Sources */, B22B6B362F673895006528EB /* ServiceDefinitionProvider.swift in Sources */, B2F55EEE2408B68F003D674C /* PSNAsia.swift in Sources */, B2253A6F209F42430039F574 /* Firebase.swift in Sources */, B22FDE512108A5C200359EC9 /* PayPalAPIProduction.swift in Sources */, B27F66AA2A3621F7008DAF33 /* AWSServices.swift in Sources */, B225E3E01E44830F008E1D3D /* SwitchableTableViewController.swift in Sources */, B22FDE4F2108A5B700359EC9 /* PayPalProductSandbox.swift in Sources */, B2F55EEC2408B5F1003D674C /* PSNAmerica.swift in Sources */, B2563BBC22CBC3D500532C39 /* DataLoader.swift in Sources */, B28E912A248250F40026BAAA /* AppleStore.swift in Sources */, B277BC9222B4BB5C000B55C3 /* AzureDevOps.swift in Sources */, B205A9181D49D67700EA178D /* Service.swift in Sources */, B228DC0C2A7F520700D8DC5E /* BetterStackService.swift in Sources */, B2A4D7E9247E73BC0089EA77 /* AzureDevOpsAll.swift in Sources */, B242AB3626E34DE9007EE672 /* SignalWire.swift in Sources */, B2DCE68D221591F2001447D8 /* LambStatusService.swift in Sources */, B200CA74247FC5AE00DB0868 /* AdobeServices.swift in Sources */, B22602AF27D87D96001190F1 /* UptimeDotCom.swift in Sources */, B22B6B422F6738CD006528EB /* SendbirdService.swift in Sources */, B22B6B432F6738CD006528EB /* IndependentService.swift in Sources */, B22B6B442F6738CD006528EB /* ServiceStore.swift in Sources */, B22FDE4821089C6200359EC9 /* PayPal.swift in Sources */, B276D7622C4132CA00974DB6 /* UptimeDotComService.swift in Sources */, B24EE10626C8C08A00F7CE8B /* SalesforceStore.swift in Sources */, B22B6B382F6738A1006528EB /* TaskExtensions.swift in Sources */, B22FDE532108A5CC00359EC9 /* PayPalAPISandbox.swift in Sources */, B2EB51CE1E7004A3001D6F78 /* ExanaService.swift in Sources */, B24EE10026C8BF9500F7CE8B /* SalesforceProducts.swift in Sources */, B2DCE6952215ACDE001447D8 /* StringExtensions.swift in Sources */, B277BC9422B4BB6D000B55C3 /* AzureDevOpsStore.swift in Sources */, 2F65F490227A198400432E64 /* Recurly.swift in Sources */, B2A4A8161DC82CE300037E99 /* BottomBar.swift in Sources */, B213A1791DC9EA25008E8E58 /* ServiceTableRowView.swift in Sources */, B2A9BFB41DC6E30F001BD4B7 /* Icons.swift in Sources */, B256955C1E247C8C00FAE413 /* PagerDuty.swift in Sources */, B23038F11E0DF3CC00B29095 /* Beanstalk.swift in Sources */, B2FBDF5F2A35D82000734667 /* IncidentIOService.swift in Sources */, B22651232B2EE1C1002F1CE2 /* PagerDutyService.swift in Sources */, B2F55EF02408B6A2003D674C /* PSNEurope.swift in Sources */, B2B77AA927FBC729009B9C2A /* FirebaseStatusDashboardStore.swift in Sources */, B22602B127D881AF001190F1 /* OracleNetSuite.swift in Sources */, B20883F32A59ADAE007578C8 /* StatusCastService.swift in Sources */, B2FC3E732A87659800A9E641 /* PreferencesWindow.swift in Sources */, B2FC3E762A8766DB00A9E641 /* PreferencesServicesView.swift in Sources */, B2FC3E782A926C2400A9E641 /* PreferencesGeneralView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; B2D0065F2A875AB5008B3A13 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( B2D006742A875B06008B3A13 /* PreferencesSidebarMenu.swift in Sources */, B2D0066F2A875AC1008B3A13 /* PreferencesWindowController.swift in Sources */, B2D006812A875AC1008B3A13 /* PreferencesAboutView.swift in Sources */, B2E5DB362F6FBE7800D71269 /* NSAppearance+Extensions.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ B2163AFB20BA4E7500B14A85 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = B2B2D0FE1D49D5080014D780 /* stts */; targetProxy = B2163AFA20BA4E7500B14A85 /* PBXContainerItemProxy */; }; B2D006682A875AB5008B3A13 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = B2D006622A875AB5008B3A13 /* PreferencesWindow */; targetProxy = B2D006672A875AB5008B3A13 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ B2B2D1061D49D5080014D780 /* MainMenu.xib */ = { isa = PBXVariantGroup; children = ( B2B2D1071D49D5080014D780 /* Base */, ); name = MainMenu.xib; path = .; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ B2163AFC20BA4E7500B14A85 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; DEAD_CODE_STRIPPING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = sttsTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", "@loader_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 11.0; PRODUCT_BUNDLE_IDENTIFIER = jp.mahdi.sttsTests; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/stts.app/Contents/MacOS/stts"; }; name = Debug; }; B2163AFD20BA4E7500B14A85 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; DEAD_CODE_STRIPPING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = sttsTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", "@loader_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 11.0; PRODUCT_BUNDLE_IDENTIFIER = jp.mahdi.sttsTests; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/stts.app/Contents/MacOS/stts"; }; name = Release; }; B2B2D10A1D49D5080014D780 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "Mac Developer"; COPY_PHASE_STRIP = NO; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = PP5UYHJQCD; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/Carthage/Build/Mac"; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = "$(SDKROOT)/usr/include/libxml2"; LD_RUNPATH_SEARCH_PATHS = "@executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; B2B2D10B1D49D5080014D780 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "Mac Developer"; COPY_PHASE_STRIP = NO; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = PP5UYHJQCD; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/Carthage/Build/Mac"; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = "$(SDKROOT)/usr/include/libxml2"; LD_RUNPATH_SEARCH_PATHS = "@executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; }; name = Release; }; B2B2D10D1D49D5080014D780 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = stts/stts.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 81; DEAD_CODE_STRIPPING = YES; ENABLE_APP_SANDBOX = YES; ENABLE_HARDENED_RUNTIME = YES; ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES; INFOPLIST_FILE = Resources/Info.plist; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools"; MACOSX_DEPLOYMENT_TARGET = 11.0; MARKETING_VERSION = 3.0; OTHER_SWIFT_FLAGS = "-Xfrontend -warn-long-function-bodies=300 -Xfrontend -warn-long-expression-type-checking=200"; PRODUCT_BUNDLE_IDENTIFIER = jp.mahdi.stts; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; name = Debug; }; B2B2D10E1D49D5080014D780 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = stts/stts.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 81; DEAD_CODE_STRIPPING = YES; ENABLE_APP_SANDBOX = YES; ENABLE_HARDENED_RUNTIME = YES; ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES; INFOPLIST_FILE = Resources/Info.plist; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools"; MACOSX_DEPLOYMENT_TARGET = 11.0; MARKETING_VERSION = 3.0; OTHER_SWIFT_FLAGS = "-Xfrontend -warn-long-function-bodies=300 -Xfrontend -warn-long-expression-type-checking=200"; PRODUCT_BUNDLE_IDENTIFIER = jp.mahdi.stts; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; name = Release; }; B2D0066C2A875AB5008B3A13 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_MODULE_VERIFIER = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 inket. All rights reserved."; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", "@loader_path/Frameworks", ); MARKETING_VERSION = 1.0; MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++20"; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = jp.mahdi.PreferencesWindow; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Debug; }; B2D0066D2A875AB5008B3A13 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_MODULE_VERIFIER = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 inket. All rights reserved."; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", "@loader_path/Frameworks", ); MARKETING_VERSION = 1.0; MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++20"; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = jp.mahdi.PreferencesWindow; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ B2163AFE20BA4E7500B14A85 /* Build configuration list for PBXNativeTarget "sttsTests" */ = { isa = XCConfigurationList; buildConfigurations = ( B2163AFC20BA4E7500B14A85 /* Debug */, B2163AFD20BA4E7500B14A85 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; B2B2D0FA1D49D5080014D780 /* Build configuration list for PBXProject "stts" */ = { isa = XCConfigurationList; buildConfigurations = ( B2B2D10A1D49D5080014D780 /* Debug */, B2B2D10B1D49D5080014D780 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; B2B2D10C1D49D5080014D780 /* Build configuration list for PBXNativeTarget "stts" */ = { isa = XCConfigurationList; buildConfigurations = ( B2B2D10D1D49D5080014D780 /* Debug */, B2B2D10E1D49D5080014D780 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; B2D0066B2A875AB5008B3A13 /* Build configuration list for PBXNativeTarget "PreferencesWindow" */ = { isa = XCConfigurationList; buildConfigurations = ( B2D0066C2A875AB5008B3A13 /* Debug */, B2D0066D2A875AB5008B3A13 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ B20883E32A59143E007578C8 /* XCRemoteSwiftPackageReference "MBPopup" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/inket/MBPopup"; requirement = { kind = upToNextMajorVersion; minimumVersion = 6.0.0; }; }; B20883E62A59144F007578C8 /* XCRemoteSwiftPackageReference "Kanna" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/tid-kijyun/Kanna"; requirement = { kind = upToNextMajorVersion; minimumVersion = 5.0.0; }; }; B20883E92A59146C007578C8 /* XCRemoteSwiftPackageReference "Reachability.swift" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/ashleymills/Reachability.swift"; requirement = { branch = master; kind = branch; }; }; B22B6B472F673BDF006528EB /* XCRemoteSwiftPackageReference "SFSafeSymbols" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/SFSafeSymbols/SFSafeSymbols"; requirement = { kind = upToNextMajorVersion; minimumVersion = 7.0.0; }; }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ B20883E42A59143E007578C8 /* MBPopup */ = { isa = XCSwiftPackageProductDependency; package = B20883E32A59143E007578C8 /* XCRemoteSwiftPackageReference "MBPopup" */; productName = MBPopup; }; B20883E72A59144F007578C8 /* Kanna */ = { isa = XCSwiftPackageProductDependency; package = B20883E62A59144F007578C8 /* XCRemoteSwiftPackageReference "Kanna" */; productName = Kanna; }; B20883EA2A59146C007578C8 /* Reachability */ = { isa = XCSwiftPackageProductDependency; package = B20883E92A59146C007578C8 /* XCRemoteSwiftPackageReference "Reachability.swift" */; productName = Reachability; }; B22B6B482F673BDF006528EB /* SFSafeSymbols */ = { isa = XCSwiftPackageProductDependency; package = B22B6B472F673BDF006528EB /* XCRemoteSwiftPackageReference "SFSafeSymbols" */; productName = SFSafeSymbols; }; B2D0067F2A875C9D008B3A13 /* SFSafeSymbols */ = { isa = XCSwiftPackageProductDependency; package = B22B6B472F673BDF006528EB /* XCRemoteSwiftPackageReference "SFSafeSymbols" */; productName = SFSafeSymbols; }; /* End XCSwiftPackageProductDependency section */ }; rootObject = B2B2D0F71D49D5080014D780 /* Project object */; } ================================================ FILE: stts.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: stts.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: stts.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved ================================================ { "originHash" : "6757785d4818500b15e48de30606d42ef095eca4264e87c401b91dbf5cd6125b", "pins" : [ { "identity" : "kanna", "kind" : "remoteSourceControl", "location" : "https://github.com/tid-kijyun/Kanna", "state" : { "revision" : "41c3d28ea0eac07e4551b28def9de1ede702e739", "version" : "5.3.0" } }, { "identity" : "mbpopup", "kind" : "remoteSourceControl", "location" : "https://github.com/inket/MBPopup", "state" : { "revision" : "67fdeb6607c75e47f5b6361125e627816d36dddc", "version" : "6.0.1" } }, { "identity" : "reachability.swift", "kind" : "remoteSourceControl", "location" : "https://github.com/ashleymills/Reachability.swift", "state" : { "branch" : "master", "revision" : "21d1dc412cfecbe6e34f1f4c4eb88d3f912654a6" } }, { "identity" : "sfsafesymbols", "kind" : "remoteSourceControl", "location" : "https://github.com/SFSafeSymbols/SFSafeSymbols", "state" : { "revision" : "e01b3d4f861412f8dcee8d93c417d2c2b0cdfd77", "version" : "7.0.0" } } ], "version" : 3 } ================================================ FILE: stts.xcodeproj/xcshareddata/xcschemes/stts.xcscheme ================================================ ================================================ FILE: sttsTests/AdobeTests.swift ================================================ // // AdobeTests.swift // sttsTests // import XCTest @testable import stts final class AdobeTests: XCTestCase { func testParsingStatus() async throws { let adobeCreativeCloud = AdobeCreativeCloudAll() let adobePremierePro = AdobePremierePro() let adobeExperienceCloud = AdobeExperienceCloudAll() // Should be .minor because Adobe Analytics is affected let adobeAnalytics = AdobeAnalytics() DataLoader.shared = DataLoader(session: ResponseOverridingURLSession(overrides: [ .init( url: BaseAdobe.store.url, response: try Data( contentsOf: Bundle.test.url(forResource: "adobe-analytics-minor", withExtension: "json")! ) ) ])) try await adobePremierePro.updateStatus() XCTAssertEqual(adobePremierePro.status, .good) try await adobeCreativeCloud.updateStatus() XCTAssertEqual(adobeCreativeCloud.status, .good) try await adobeAnalytics.updateStatus() XCTAssertEqual(adobeAnalytics.status, .minor) try await adobeExperienceCloud.updateStatus() XCTAssertEqual(adobeExperienceCloud.status, .minor) } } ================================================ FILE: sttsTests/BetterStackTests.swift ================================================ // // BetterStackTests.swift // sttsTests // import XCTest @testable import stts final class BetterStackTests: XCTestCase { private func createService() throws -> BetterStackService { let definition = try JSONDecoder().decode( BetterStackServiceDefinition.self, from: Data(""" { "url": "https://status.buildjet.com", "name": "BuildJet" } """.utf8) ) return try XCTUnwrap(definition.build() as? BetterStackService) } func testNormalStatus() async throws { let buildJet = try createService() DataLoader.shared = DataLoader(session: ResponseOverridingURLSession(overrides: [ .init( url: buildJet.url, response: try Data( contentsOf: Bundle.test.url(forResource: "buildjet-good", withExtension: "html")! ) ) ])) try await buildJet.updateStatus() XCTAssertEqual(buildJet.status, .good) } func testMajorStatus() async throws { let buildJet = try createService() DataLoader.shared = DataLoader(session: ResponseOverridingURLSession(overrides: [ .init( url: buildJet.url, response: try Data( contentsOf: Bundle.test.url(forResource: "eyloo-major", withExtension: "html")! ) ) ])) try await buildJet.updateStatus() XCTAssertEqual(buildJet.status, .major) } } ================================================ FILE: sttsTests/Helpers/TestBundle.swift ================================================ // // TestBundle.swift // sttsTests // import Foundation private class TestBundle {} extension Bundle { static var test: Bundle { Bundle(for: TestBundle.self) } } ================================================ FILE: sttsTests/IncidentIOTests.swift ================================================ // // IncidentIOTests.swift // sttsTests // import XCTest @testable import stts final class IncidentIOTests: XCTestCase { private func createAivenService() throws -> IncidentIOService { let definition = try JSONDecoder().decode( IncidentIOServiceDefinition.self, from: Data(""" { "name": "Aiven", "url": "https://status.aiven.io" } """.utf8) ) return try XCTUnwrap(definition.build() as? IncidentIOService) } private func createLinearService() throws -> IncidentIOService { let definition = try JSONDecoder().decode( IncidentIOServiceDefinition.self, from: Data(""" { "name": "Linear", "url": "https://linearstatus.com" } """.utf8) ) return try XCTUnwrap(definition.build() as? IncidentIOService) } private func createOpenAIService() throws -> IncidentIOService { let definition = try JSONDecoder().decode( IncidentIOServiceDefinition.self, from: Data(""" { "name": "OpenAI", "url": "https://status.openai.com" } """.utf8) ) return try XCTUnwrap(definition.build() as? IncidentIOService) } private func createRollbarService() throws -> IncidentIOService { let definition = try JSONDecoder().decode( IncidentIOServiceDefinition.self, from: Data(""" { "name": "Rollbar", "url": "https://status.rollbar.com" } """.utf8) ) return try XCTUnwrap(definition.build() as? IncidentIOService) } func testMinorStatus() async throws { let aiven = try createAivenService() DataLoader.shared = DataLoader(session: ResponseOverridingURLSession(overrides: [ .init( url: aiven.url, response: try Data( contentsOf: Bundle.test.url(forResource: "aiven-minor", withExtension: "html")! ) ) ])) try await aiven.updateStatus() XCTAssertEqual(aiven.status, .minor) XCTAssertEqual(aiven.message, "We\u{2019}re currently experiencing issues\n* Amazon Web Services (AWS) ME-CENTRAL-1 region status") } func testGoodStatus() async throws { let linear = try createLinearService() DataLoader.shared = DataLoader(session: ResponseOverridingURLSession(overrides: [ .init( url: linear.url, response: try Data( contentsOf: Bundle.test.url(forResource: "linear-good", withExtension: "html")! ) ) ])) try await linear.updateStatus() XCTAssertEqual(linear.status, .good) XCTAssertEqual(linear.message, "We\u{2019}re fully operational") } func testMajorStatus() async throws { let openai = try createOpenAIService() DataLoader.shared = DataLoader(session: ResponseOverridingURLSession(overrides: [ .init( url: openai.url, response: try Data( contentsOf: Bundle.test.url(forResource: "openai-major", withExtension: "html")! ) ) ])) try await openai.updateStatus() XCTAssertEqual(openai.status, .major) XCTAssertEqual( openai.message, "We\u{2019}re currently experiencing issues\n* Elevated errors for sign-in and account creation" ) } func testGoodStatusFromLiIcon() async throws { let rollbar = try createRollbarService() DataLoader.shared = DataLoader(session: ResponseOverridingURLSession(overrides: [ .init( url: rollbar.url, response: try Data( contentsOf: Bundle.test.url(forResource: "rollbar-good", withExtension: "html")! ) ) ])) try await rollbar.updateStatus() XCTAssertEqual(rollbar.status, .good) XCTAssertEqual(rollbar.message, "We\u{2019}re fully operational") } } ================================================ FILE: sttsTests/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleVersion 1 ================================================ FILE: sttsTests/InstatusTests.swift ================================================ // // InstatusTests.swift // sttsTests // import XCTest @testable import stts final class InstatusTests: XCTestCase { private func createMastodonSocialService() throws -> InstatusService { let definition = try JSONDecoder().decode( InstatusServiceDefinition.self, from: Data(""" { "name": "mastodon.social", "url": "https://status.mastodon.social", "old_names": [ "MastodonSocial" ] } """.utf8) ) return try XCTUnwrap(definition.build() as? InstatusService) } private func createWherebyService() throws -> InstatusService { let definition = try JSONDecoder().decode( InstatusServiceDefinition.self, from: Data(""" { "url": "https://wherebystatus.com", "name": "Whereby" } """.utf8) ) return try XCTUnwrap(definition.build() as? InstatusService) } func testMajorStatus() async throws { let mastodonSocial = try createMastodonSocialService() DataLoader.shared = DataLoader(session: ResponseOverridingURLSession(overrides: [ .init( url: mastodonSocial.url, response: try Data( contentsOf: Bundle.test.url(forResource: "mastodonsocial-major", withExtension: "html")! ) ) ])) try await mastodonSocial.updateStatus() XCTAssertEqual(mastodonSocial.status, .major) } func testNormalStatus() async throws { let whereby = try createWherebyService() DataLoader.shared = DataLoader(session: ResponseOverridingURLSession(overrides: [ .init( url: whereby.url, response: try Data(contentsOf: Bundle.test.url( forResource: "whereby-good", withExtension: "html" )!) ) ])) try await whereby.updateStatus() XCTAssertEqual(whereby.status, .good) } } ================================================ FILE: sttsTests/MiroTests.swift ================================================ // // MiroTests.swift // sttsTests // import XCTest @testable import stts final class MiroTests: XCTestCase { private func createService() -> MiroAll { MiroAll() } func testGoodStatus() async throws { let miro = createService() DataLoader.shared = DataLoader(session: ResponseOverridingURLSession(overrides: [ .init( url: miro.url, response: try Data( contentsOf: Bundle.test.url(forResource: "miro-good", withExtension: "html")! ) ) ])) try await miro.updateStatus() XCTAssertEqual(miro.status, .good) XCTAssertEqual(miro.message, "We\u{2019}re fully operational") } func testIssueStatus() async throws { let miro = createService() DataLoader.shared = DataLoader(session: ResponseOverridingURLSession(overrides: [ .init( url: miro.url, response: try Data( contentsOf: Bundle.test.url(forResource: "miro-issue", withExtension: "html")! ) ) ])) try await miro.updateStatus() XCTAssertEqual(miro.status, .major) XCTAssertEqual(miro.message, "EU: We\u{2019}re currently experiencing issues") } } ================================================ FILE: sttsTests/Mocks/ResponseOverridingURLSession.swift ================================================ // // ResponseOverridingURLSession.swift // sttsTests // import Foundation import stts final class ResponseOverridingURLSession: URLSessionProtocol { class Override { let url: URL let response: Data init(url: URL, response: Data) { self.url = url self.response = response } } let overrides: [URL: Override] init(overrides: [Override]) { var mappedOverrides: [URL: Override] = [:] overrides.forEach { mappedOverrides[$0.url] = $0 } self.overrides = mappedOverrides } func data(from url: URL) async throws -> (Data, URLResponse) { if let override = overrides[url] { print("[ResponseOverridingURLSession] Overridden URL: \(url)") try await Task.sleep(seconds: 0.5) return (override.response, URLResponse()) } else { print("[ResponseOverridingURLSession] Skipped URL: \(url)") return try await URLSession.shared.data(from: url) } } func data(for request: URLRequest) async throws -> (Data, URLResponse) { if let override = overrides[request.url!] { print("[ResponseOverridingURLSession] Overridden request URL: \(String(describing: request.url))") try await Task.sleep(seconds: 0.5) return (override.response, URLResponse()) } else { print("[ResponseOverridingURLSession] Skipped URL: \(String(describing: request.url))") return try await URLSession.shared.data(for: request) } } } ================================================ FILE: sttsTests/Mocks/ResponseSizeTrackingURLSession.swift ================================================ // // ResponseSizeTrackingURLSession.swift // sttsTests // import Foundation import stts final class ResponseSizeTrackingURLSession: URLSessionProtocol { private func humanSize(data: Data?) -> String { guard let data = data else { return "nil" } return "\(data.count / 1024)KB" } func data(from url: URL) async throws -> (Data, URLResponse) { let (data, response) = try await URLSession.shared.data(from: url) print("[ResponseSizeTrackingURLSession] \(humanSize(data: data)) [\(url.absoluteString)]") return (data, response) } func data(for request: URLRequest) async throws -> (Data, URLResponse) { let (data, response) = try await URLSession.shared.data(for: request) print("[ResponseSizeTrackingURLSession] \(humanSize(data: data)) [\(request.url?.absoluteString ?? "nil")]") return (data, response) } } ================================================ FILE: sttsTests/PagerDutyTests.swift ================================================ // // PagerDutyTests.swift // sttsTests // import XCTest @testable import stts final class PagerDutyTests: XCTestCase { func testNormalStatus() async throws { let pagerDuty = PagerDuty() DataLoader.shared = DataLoader(session: ResponseOverridingURLSession(overrides: [ .init( url: pagerDuty.url, response: try Data(contentsOf: Bundle.test.url(forResource: "pagerduty-good", withExtension: "html")!) ) ])) try await pagerDuty.updateStatus() XCTAssertEqual(pagerDuty.status, .good) XCTAssertEqual(pagerDuty.message, "No known issue") } func testMinorStatus() async throws { let pagerDuty = PagerDuty() DataLoader.shared = DataLoader(session: ResponseOverridingURLSession(overrides: [ .init( url: pagerDuty.url, response: try Data(contentsOf: Bundle.test.url( forResource: "pagerduty-minor", withExtension: "html" )!) ) ])) try await pagerDuty.updateStatus() XCTAssertEqual(pagerDuty.status, .minor) XCTAssertEqual(pagerDuty.message, "Inconsistent Service Statuses") } } ================================================ FILE: sttsTests/Resources/adobe-analytics-minor.json ================================================ [File too large to display: 13.6 MB] ================================================ FILE: sttsTests/Resources/aiven-minor.html ================================================ Aiven Status ================================================ FILE: sttsTests/Resources/buildjet-good.html ================================================ BuildJet status

All services are online

Last updated on Aug 06 at 09:42am CEST

Website
Dashboard
GitHub Actions Job Execution
================================================ FILE: sttsTests/Resources/eyloo-major.html ================================================ Eyloo Services status

Some services are down

Last updated on Aug 06 at 09:41am CEST

Website
30 days ago
Today
Kundenbereich
30 days ago
Today
TestDrive
30 days ago
Today
================================================ FILE: sttsTests/Resources/linear-good.html ================================================ Linear Status
  • We’re fully operational
  • We’re not aware of any issues affecting our systems.

    System status

    US Region – Linear application

    US Region – Linear API

    US Region – Integrations

    EU Region – Linear application

    EU Region – Linear API

    EU Region – Integrations

    Calendar

    Mar 2026
    Loading...
    M
    T
    W
    T
    F
    S
    S
    ================================================ FILE: sttsTests/Resources/mastodonsocial-major.html ================================================ mastodon.social - Status

    mastodon.social - Status Page

    Experiencing partial outage

    Website & API - Major outage

    79% - uptime

    Background queues - Major outage

    79% - uptime

    Media storage - Operational

    100% - uptime

    Streaming API - Major outage

    79% - uptime

    Recent notices

    No notices reported for the past 7 days

    Show notice history
    ================================================ FILE: sttsTests/Resources/miro-good.html ================================================ Miro Status

    Miro

    The status of Miro and all related services is constantly monitored and updated on this site. 

    To view the latest status for Miro, please select the appropriate data residency region for your application below.

    By default, Customer Content is hosted in the EU. 

    However, some Enterprise Plan customers host data in the US or Australia exclusively. If you're unsure about your hosting location, please contact your organization's administrator for assistance.

    If you're unable to access Miro and there is no information posted here, please contact us via this form. Feel free to subscribe to updates to receive information about upcoming scheduled maintenance, incidents, etc.

    Powered by
    ================================================ FILE: sttsTests/Resources/miro-issue.html ================================================ Miro Status

    Miro

    The status of Miro and all related services is constantly monitored and updated on this site. 

    To view the latest status for Miro, please select the appropriate data residency region for your application below.

    By default, Customer Content is hosted in the EU. 

    However, some Enterprise Plan customers host data in the US or Australia exclusively. If you're unsure about your hosting location, please contact your organization's administrator for assistance.

    If you're unable to access Miro and there is no information posted here, please contact us via this form. Feel free to subscribe to updates to receive information about upcoming scheduled maintenance, incidents, etc.

    Powered by
    ================================================ FILE: sttsTests/Resources/openai-major.html ================================================ OpenAI Status

    OpenAI

    System status

    APIs

    ChatGPT

    Sora

    FedRAMP

    Powered by

    Availability metrics are reported at an aggregate level across all tiers, models and error types. Individual customer availability may vary depending on their subscription tier as well as the specific model and API features in use.

    ================================================ FILE: sttsTests/Resources/pagerduty-good.html ================================================ Status Page
    ================================================ FILE: sttsTests/Resources/pagerduty-minor.html ================================================ Status Page
    ================================================ FILE: sttsTests/Resources/rollbar-good.html ================================================ Rollbar Status
  • We’re fully operational
  • We’re not aware of any issues affecting our systems.

    System status

    Web Tier

    API Tier (api.rollbar.com)

    Processing pipeline

    External notification services

    rollbar.min.js

    SCIM and SSO

    Rollbar Docs

    Calendar

    Mar 2026
    Loading...
    M
    T
    W
    T
    F
    S
    S
    ================================================ FILE: sttsTests/Resources/whereby-good.html ================================================ Whereby - Status

    Whereby - Status Page

    Meeting rooms - Operational

    100% - uptime

    Embedded API - Operational

    100% - uptime

    Admin dashboard - Operational

    100% - uptime

    whereby.com - Operational

    100% - uptime

    Recent notices

    No notices reported for the past 7 days

    Show notice history
    ================================================ FILE: sttsTests/StringExtensionsTests.swift ================================================ // // StringExtensionsTests.swift // sttsTests // import XCTest @testable import stts class StringExtensionsTests: XCTestCase { func testInnerJSONStringWithNewLine() throws { XCTAssertEqual("jsonCallback(✅);\n".innerJSONString, "✅") XCTAssertEqual("jsonCallback(✅); \n\n\n ".innerJSONString, "✅") } func testInnerJSONStringWithoutNewLine() throws { XCTAssertEqual("jsonCallback(✅);".innerJSONString, "✅") } func testInnerJSONStringOther() throws { XCTAssertEqual("out of scope".innerJSONString, "out of scope") } func testUnescapedWithNonEscapedString() throws { XCTAssertEqual("Test this!".unescaped, "Test this!") } func testUnescapedWithHardcodedEscapedString() throws { XCTAssertEqual("Test this!ç\n\u{003e}".unescaped, "Test this!ç\n\u{003e}") } func testUnescapedWithEscapedString() throws { XCTAssertEqual("\\\"test\\\"".unescaped, "\"test\"") XCTAssertEqual(#"\"test\""#.unescaped, #""test""#) } func testUnescapedWithEscapedUnicodeCodePointsString() throws { XCTAssertEqual(#"\u003cp\u003eHTML

    "#.unescaped, #"

    HTML

    "#) } func testUnescapedWithJSONString() throws { // swiftlint:disable:next line_length XCTAssertEqual(#"{\"id\":\"aaa\",\"name\":\"Dashboard\",\"nameHtml\":\"\u003cp\u003eDashboard\u003c/p\u003e\",\"description\":\"\",\"descriptionHtml\":\"\",\"nameTranslation\":null,\"nameHtmlTranslation\":null,\"descriptionTranslation\":null,\"descriptionHtmlTranslation\":null,\"isCollapsed\":false,\"order\":1}"#.unescaped, #"{"id":"aaa","name":"Dashboard","nameHtml":"

    Dashboard

    ","description":"","descriptionHtml":"","nameTranslation":null,"nameHtmlTranslation":null,"descriptionTranslation":null,"descriptionHtmlTranslation":null,"isCollapsed":false,"order":1}"#) } func testUnescapedWithTrickyLineBreak() throws { XCTAssertEqual("\\\\n".unescaped, "\\n") } } ================================================ FILE: sttsTests/sttsTests.swift ================================================ // // sttsTests.swift // sttsTests // import XCTest @testable import stts class SttsTests: XCTestCase { override func setUpWithError() throws { DataLoader.shared = DataLoader(session: ResponseSizeTrackingURLSession()) } func testServices() async throws { var serviceDefinitionProviders: [ServiceDefinitionProvider] = [] // swiftlint:disable:next force_try serviceDefinitionProviders.append(try! AppDefinedServiceDefinitionProvider()) // swiftlint:disable:next force_try serviceDefinitionProviders.append(try! BundleServiceDefinitionProvider()) if let userDefinedServiceDefinitionsProvider = try? UserDefinedServiceDefinitionProvider() { serviceDefinitionProviders.append(userDefinedServiceDefinitionsProvider) } let serviceDefinitions = ServiceLoader(providers: serviceDefinitionProviders).allServices var testedServices: [BaseService] = [] // Have to retain services until the end of the test print("Retrieving status for \(serviceDefinitions.count) services") await withTaskGroup(of: Void.self) { group in var sleepDuration: TimeInterval = 0 for serviceDefinition in serviceDefinitions { guard let service = serviceDefinition.build() as? Service else { XCTFail("Could not build service for definition: \(serviceDefinition)") return } testedServices.append(service) if service is StatusPageService { // Status page servers don't like being hammered by this many requests, so we slow it down. // I really wish they would add an API for querying the status of many services at once. sleepDuration += 1 } print("Retrieving status for \(service.name)…") group.addTask { [sleepDuration] in do { try await Task.sleep(seconds: sleepDuration) try await service.updateStatus() print( """ Retrieved status for \(service.name): \(service.status)\ (\(service.message)) """ ) XCTAssert( service.status != .undetermined, "Retrieved status for \(service.name) should not be .undetermined" ) } catch { XCTFail("Failed retrieving status for \(service.name): \(error)") } } } } testedServices = [] } }