> ## Documentation Index
> Fetch the complete documentation index at: https://docs2.growthbook.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Python SDK

> GrowthBook SDK for Python

export const SdkSupportedFeatures = ({sdk}) => {
  const sdkInfo = {
    js: {
      name: "JS SDK",
      version: "1.7.0",
      github: "https://github.com/growthbook/growthbook/tree/main/packages/sdk-js",
      examples: [{
        url: "https://github.com/growthbook/examples/tree/main/vanilla-typescript",
        name: "Typescript example app"
      }],
      packageRepos: [{
        name: "npm",
        url: "https://www.npmjs.com/package/@growthbook/growthbook"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        contextualBandits: "≥ v1.7.0"
      }, {
        caseInsensitiveMembership: "≥ v1.6.4"
      }, {
        caseInsensitiveRegex: "≥ v1.6.3"
      }, {
        trackingPlugin: "≥ v1.4.0"
      }, {
        savedGroupReferences: "≥ v1.1.0"
      }, {
        redirects: "≥ v0.36.0"
      }, {
        prerequisites: "≥ v0.34.0"
      }, {
        stickyBucketing: "≥ v0.32.0"
      }, {
        visualEditorDragDrop: "≥ v0.30.0"
      }, {
        remoteEval: "≥ v0.29.0"
      }, {
        semverTargeting: "≥ v0.27.0"
      }, {
        visualEditorJS: "≥ v0.27.0"
      }, {
        visualEditor: "≥ v0.24.0"
      }, {
        bucketingV2: "≥ v0.23.0"
      }, {
        streaming: "≥ v0.21.0"
      }, {
        encryption: "≥ v0.20.0"
      }, {
        looseUnmarshalling: "≥ v0.0.0"
      }, {
        namespacesV2: "≥ v0.0.0"
      }]
    },
    react: {
      name: "React SDK",
      version: "1.7.0",
      github: "https://github.com/growthbook/growthbook/tree/main/packages/sdk-react",
      examples: [{
        url: "https://github.com/growthbook/examples/tree/main/next-js",
        name: "Next.js example app"
      }, {
        url: "https://github.com/growthbook/examples/tree/main/next-js-pages",
        name: "Next.js pages example app"
      }, {
        url: "https://docs.growthbook.io/guide/create-react-app-and-growthbook",
        name: "Create React App guide"
      }],
      packageRepos: [{
        name: "npm",
        url: "https://www.npmjs.com/package/@growthbook/growthbook-react"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        contextualBandits: "≥ v1.7.0"
      }, {
        caseInsensitiveMembership: "≥ v1.6.4"
      }, {
        caseInsensitiveRegex: "≥ v1.6.3"
      }, {
        trackingPlugin: "≥ v1.4.0"
      }, {
        savedGroupReferences: "≥ v1.1.0"
      }, {
        redirects: "≥ v0.26.0"
      }, {
        prerequisites: "≥ v0.24.0"
      }, {
        stickyBucketing: "≥ v0.22.0"
      }, {
        visualEditorDragDrop: "≥ v0.20.0"
      }, {
        remoteEval: "≥ v0.19.0"
      }, {
        semverTargeting: "≥ v0.17.0"
      }, {
        visualEditorJS: "≥ v0.17.0"
      }, {
        visualEditor: "≥ v0.14.0"
      }, {
        bucketingV2: "≥ v0.13.0"
      }, {
        streaming: "≥ v0.11.0"
      }, {
        encryption: "≥ v0.10.1"
      }, {
        looseUnmarshalling: "≥ v0.0.0"
      }, {
        namespacesV2: "≥ v0.0.0"
      }]
    },
    nextjs: {
      name: "Next.js SDK",
      version: "0.1.0",
      github: "https://github.com/vercel/flags/tree/main/packages/adapter-growthbook",
      examples: [{
        url: "https://github.com/vercel/examples/tree/main/flags-sdk/growthbook",
        name: "Next.js Flags SDK example app"
      }],
      packageRepos: [{
        name: "npm",
        url: "https://www.npmjs.com/package/@flags-sdk/growthbook"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        savedGroupReferences: "≥ v0.1.0"
      }, {
        redirects: "≥ v0.1.0"
      }, {
        prerequisites: "≥ v0.1.0"
      }, {
        stickyBucketing: "≥ v0.1.0"
      }, {
        semverTargeting: "≥ v0.1.0"
      }, {
        bucketingV2: "≥ v0.1.0"
      }, {
        encryption: "≥ v0.1.0"
      }, {
        looseUnmarshalling: "≥ v0.1.0"
      }, {
        namespacesV2: "≥ v0.1.0"
      }]
    },
    php: {
      name: "PHP SDK",
      version: "2.6.1",
      github: "https://github.com/growthbook/growthbook-php",
      examples: [],
      packageRepos: [{
        name: "Packagist (Composer)",
        url: "https://packagist.org/packages/growthbook/growthbook"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        remoteEval: "≥ v2.5.0"
      }, {
        trackingPlugin: "≥ v2.4.0"
      }, {
        caseInsensitiveRegex: "≥ v2.3.0"
      }, {
        caseInsensitiveMembership: "≥ v2.3.0"
      }, {
        savedGroupReferences: "≥ v1.7.0"
      }, {
        prerequisites: "≥ v1.6.0"
      }, {
        stickyBucketing: "≥ v1.6.0"
      }, {
        semverTargeting: "≥ v1.5.0"
      }, {
        bucketingV2: "≥ v1.2.0"
      }, {
        encryption: "≥ v1.2.0"
      }, {
        looseUnmarshalling: "≥ v1.0.0"
      }, {
        namespacesV2: "≥ v1.0.0"
      }]
    },
    node: {
      name: "Node SDK",
      version: "1.7.0",
      github: "https://github.com/growthbook/growthbook/tree/main/packages/sdk-js",
      examples: [{
        url: "https://docs.growthbook.io/guide/express-js",
        name: "Express.js guide"
      }],
      packageRepos: [{
        name: "npm",
        url: "https://www.npmjs.com/package/@growthbook/growthbook"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        contextualBandits: "≥ v1.7.0"
      }, {
        caseInsensitiveMembership: "≥ v1.6.4"
      }, {
        caseInsensitiveRegex: "≥ v1.6.3"
      }, {
        trackingPlugin: "≥ v1.4.0"
      }, {
        savedGroupReferences: "≥ v1.1.0"
      }, {
        redirects: "≥ v0.36.0"
      }, {
        prerequisites: "≥ v0.34.0"
      }, {
        stickyBucketing: "≥ v0.32.0"
      }, {
        semverTargeting: "≥ v0.27.0"
      }, {
        bucketingV2: "≥ v0.23.0"
      }, {
        streaming: "≥ v0.21.0"
      }, {
        encryption: "≥ v0.20.0"
      }, {
        looseUnmarshalling: "≥ v0.0.0"
      }, {
        namespacesV2: "≥ v0.0.0"
      }]
    },
    ruby: {
      name: "Ruby SDK",
      version: "1.3.0",
      github: "https://github.com/growthbook/growthbook-ruby",
      examples: [{
        url: "https://github.com/growthbook/examples/tree/main/acme_donuts_rails",
        name: "Rails example app"
      }],
      packageRepos: [{
        name: "RubyGems",
        url: "https://rubygems.org/gems/growthbook"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        prerequisites: "≥ v1.3.0"
      }, {
        stickyBucketing: "≥ v1.3.0"
      }, {
        semverTargeting: "≥ v1.2.2"
      }, {
        encryption: "≥ v1.1.0"
      }, {
        bucketingV2: "≥ v1.0.0"
      }, {
        looseUnmarshalling: "≥ v0.0.0"
      }, {
        namespacesV2: "≥ v0.0.0"
      }]
    },
    python: {
      name: "Python SDK",
      version: "2.4.0",
      github: "https://github.com/growthbook/growthbook-python",
      examples: [],
      packageRepos: [{
        name: "PyPi",
        url: "https://pypi.org/project/growthbook/"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        remoteEval: "≥ v2.3.0"
      }, {
        trackingPlugin: "≥ v2.2.0"
      }, {
        caseInsensitiveMembership: "≥ v2.1.1"
      }, {
        caseInsensitiveRegex: "≥ v2.1.0"
      }, {
        savedGroupReferences: "≥ v1.2.1"
      }, {
        looseUnmarshalling: "≥ v1.1.0"
      }, {
        namespacesV2: "≥ v1.1.0"
      }, {
        prerequisites: "≥ v1.1.0"
      }, {
        stickyBucketing: "≥ v1.1.0"
      }, {
        semverTargeting: "≥ v1.1.0"
      }, {
        bucketingV2: "≥ v1.0.0"
      }, {
        encryption: "≥ v1.0.0"
      }]
    },
    go: {
      name: "Go SDK",
      version: "0.2.9",
      github: "https://github.com/growthbook/growthbook-golang",
      examples: [{
        url: "https://github.com/growthbook/examples/tree/main/go-example",
        name: "Go example app"
      }],
      packageRepos: [{
        name: "Go Modules",
        url: "https://pkg.go.dev/github.com/growthbook/growthbook-golang"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        trackingPlugin: "≥ v0.2.8"
      }, {
        caseInsensitiveMembership: "≥ v0.2.7"
      }, {
        caseInsensitiveRegex: "≥ v0.2.7"
      }, {
        stickyBucketing: "≥ v0.2.3"
      }, {
        prerequisites: "≥ v0.2.0"
      }, {
        savedGroupReferences: "≥ v0.2.0"
      }, {
        bucketingV2: "≥ v0.1.4"
      }, {
        streaming: "≥ v0.1.4"
      }, {
        semverTargeting: "≥ v0.1.4"
      }, {
        encryption: "≥ v0.1.4"
      }, {
        looseUnmarshalling: "≥ v0.0.0"
      }, {
        namespacesV2: "≥ v0.0.0"
      }]
    },
    rust: {
      name: "Rust SDK",
      version: "0.2.1",
      github: "https://github.com/growthbook/growthbook-rust",
      examples: [{
        url: "https://github.com/growthbook/growthbook-rust/tree/main/examples/client",
        name: "Rust example app"
      }],
      packageRepos: [{
        name: "crates.io",
        url: "https://crates.io/crates/growthbook-rust"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        savedGroupReferences: "≥ v0.2.0"
      }, {
        caseInsensitiveRegex: "≥ v0.1.1"
      }, {
        caseInsensitiveMembership: "≥ v0.1.1"
      }, {
        stickyBucketing: "≥ v0.1.0"
      }, {
        encryption: "≥ v0.0.1"
      }, {
        looseUnmarshalling: "≥ v0.0.1"
      }, {
        namespacesV2: "≥ v0.0.1"
      }, {
        prerequisites: "≥ v0.0.1"
      }, {
        semverTargeting: "≥ v0.0.1"
      }, {
        bucketingV2: "≥ v0.0.1"
      }]
    },
    java: {
      name: "Java SDK",
      version: "0.10.10",
      github: "https://github.com/growthbook/growthbook-sdk-java",
      examples: [{
        url: "https://github.com/growthbook/examples/tree/main/jvm-spring-web",
        name: "JVM with Spring Web example app"
      }, {
        url: "https://github.com/growthbook/examples/tree/main/jvm-kotlin-ktor-example",
        name: "JVM with Kotlin Ktor example app"
      }, {
        url: "https://github.com/growthbook/examples/tree/main/android-example",
        name: "Android example app"
      }, {
        url: "https://growthbook.github.io/growthbook-sdk-java/",
        name: "JavaDoc class docs"
      }],
      packageRepos: [{
        name: "JitPack",
        url: "https://jitpack.io/#growthbook/growthbook-sdk-java"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        caseInsensitiveMembership: "≥ v0.10.9"
      }, {
        caseInsensitiveRegex: "≥ v0.10.6"
      }, {
        remoteEval: "≥ v0.9.92"
      }, {
        prerequisites: "≥ v0.9.3"
      }, {
        stickyBucketing: "≥ v0.9.3"
      }, {
        streaming: "≥ v0.9.0"
      }, {
        semverTargeting: "≥ v0.7.0"
      }, {
        bucketingV2: "≥ v0.6.0"
      }, {
        encryption: "≥ v0.3.0"
      }, {
        looseUnmarshalling: "≥ v0.0.0"
      }, {
        namespacesV2: "≥ v0.0.0"
      }]
    },
    csharp: {
      name: "C# SDK",
      version: "1.2.0",
      github: "https://github.com/growthbook/growthbook-c-sharp",
      examples: [{
        url: "https://github.com/growthbook/examples/tree/main/csharp-example/GrowthBookCSharpExamples",
        name: "C# example app"
      }],
      packageRepos: [{
        name: "NuGet",
        url: "https://www.nuget.org/packages/growthbook-c-sharp"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        caseInsensitiveMembership: "≥ v1.2.0"
      }, {
        caseInsensitiveRegex: "≥ v1.2.0"
      }, {
        remoteEval: "≥ v1.1.3"
      }, {
        stickyBucketing: "≥ v1.1.0"
      }, {
        prerequisites: "≥ v1.1.0"
      }, {
        savedGroupReferences: "≥ v1.1.0"
      }, {
        encryption: "≥ v1.0.0"
      }, {
        streaming: "≥ v1.0.0"
      }, {
        bucketingV2: "≥ v1.0.0"
      }, {
        semverTargeting: "≥ v1.0.0"
      }, {
        looseUnmarshalling: "≥ v0.0.0"
      }, {
        namespacesV2: "≥ v0.0.0"
      }]
    },
    elixir: {
      name: "Elixir SDK",
      version: "0.3.0",
      github: "https://github.com/growthbook/growthbook-elixir",
      examples: [],
      packageRepos: [{
        name: "Hex",
        url: "https://www.hex.pm/packages/growthbook"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        encryption: "≥ v0.3.0"
      }, {
        prerequisites: "≥ v0.2.0"
      }, {
        semverTargeting: "≥ v0.2.0"
      }, {
        bucketingV2: "≥ v0.2.0"
      }, {
        looseUnmarshalling: "≥ v0.2.0"
      }, {
        namespacesV2: "≥ v0.2.0"
      }]
    },
    kotlin: {
      name: "Kotlin SDK",
      version: "7.6.0",
      github: "https://github.com/growthbook/growthbook-kotlin",
      examples: [],
      packageRepos: [{
        name: "Maven Central",
        url: "https://mvnrepository.com/artifact/io.growthbook.sdk/GrowthBook"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        caseInsensitiveMembership: "≥ v7.1.1"
      }, {
        caseInsensitiveRegex: "≥ v7.1.1"
      }, {
        remoteEval: "≥ v1.1.50"
      }, {
        streaming: "≥ v1.1.50"
      }, {
        prerequisites: "≥ v1.1.44"
      }, {
        stickyBucketing: "≥ v1.1.44"
      }, {
        bucketingV2: "≥ v1.1.38"
      }, {
        semverTargeting: "≥ v1.1.31"
      }, {
        encryption: "≥ v1.1.23"
      }, {
        looseUnmarshalling: "≥ v0.0.0"
      }, {
        namespacesV2: "≥ v0.0.0"
      }]
    },
    swift: {
      name: "Swift SDK",
      version: "1.2.0",
      github: "https://github.com/growthbook/growthbook-swift",
      examples: [],
      packageRepos: [{
        name: "Swift Package Manager (SPM)",
        url: "https://swiftpackageindex.com/growthbook/growthbook-swift"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        namespacesV2: "≥ v1.1.4"
      }, {
        caseInsensitiveMembership: "≥ v1.1.1"
      }, {
        caseInsensitiveRegex: "≥ v1.1.1"
      }, {
        remoteEval: "≥ v1.0.50"
      }, {
        stickyBucketing: "≥ v1.0.49"
      }, {
        prerequisites: "≥ v1.0.49"
      }, {
        bucketingV2: "≥ v1.0.43"
      }, {
        streaming: "≥ v1.0.43"
      }, {
        semverTargeting: "≥ v1.0.38"
      }, {
        encryption: "≥ v1.0.35"
      }, {
        looseUnmarshalling: "≥ v0.0.0"
      }]
    },
    reactNative: {
      name: "React Native SDK",
      version: "1.7.0",
      github: "https://github.com/growthbook/growthbook/tree/main/packages/sdk-react",
      examples: [{
        url: "https://github.com/growthbook/examples/tree/main/react-native-cli",
        name: "React Native CLI example app"
      }],
      packageRepos: [{
        name: "npm",
        url: "https://www.npmjs.com/package/@growthbook/growthbook-react"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        contextualBandits: "≥ v1.7.0"
      }, {
        caseInsensitiveMembership: "≥ v1.6.4"
      }, {
        caseInsensitiveRegex: "≥ v1.6.3"
      }, {
        trackingPlugin: "≥ v1.4.0"
      }, {
        savedGroupReferences: "≥ v1.1.0"
      }, {
        redirects: "≥ v0.26.0"
      }, {
        prerequisites: "≥ v0.24.0"
      }, {
        stickyBucketing: "≥ v0.22.0"
      }, {
        visualEditorDragDrop: "≥ v0.20.0"
      }, {
        remoteEval: "≥ v0.19.0"
      }, {
        semverTargeting: "≥ v0.17.0"
      }, {
        visualEditorJS: "≥ v0.17.0"
      }, {
        visualEditor: "≥ v0.14.0"
      }, {
        bucketingV2: "≥ v0.13.0"
      }, {
        streaming: "≥ v0.11.0"
      }, {
        encryption: "≥ v0.10.1"
      }, {
        looseUnmarshalling: "≥ v0.0.0"
      }, {
        namespacesV2: "≥ v0.0.0"
      }]
    },
    edgeCloudflare: {
      name: "Cloudflare Workers App & SDK",
      version: "0.2.9",
      github: "https://github.com/growthbook/growthbook-proxy/tree/main/packages/lib/edge-cloudflare",
      examples: [{
        url: "https://github.com/growthbook/growthbook-proxy/tree/main/packages/lib/edge-cloudflare/example",
        name: "Example worker"
      }],
      packageRepos: [{
        name: "npm",
        url: "https://www.npmjs.com/package/@growthbook/edge-cloudflare"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        caseInsensitiveRegex: "≥ v0.2.7"
      }, {
        caseInsensitiveMembership: "≥ v0.2.7"
      }, {
        savedGroupReferences: "≥ v0.1.12"
      }, {
        looseUnmarshalling: "≥ v0.1.11"
      }, {
        namespacesV2: "≥ v0.1.11"
      }, {
        encryption: "≥ v0.1.11"
      }, {
        streaming: "≥ v0.1.11"
      }, {
        bucketingV2: "≥ v0.1.11"
      }, {
        visualEditor: "≥ v0.1.11"
      }, {
        semverTargeting: "≥ v0.1.11"
      }, {
        visualEditorJS: "≥ v0.1.11"
      }, {
        visualEditorDragDrop: "≥ v0.1.11"
      }, {
        prerequisites: "≥ v0.1.11"
      }, {
        redirects: "≥ v0.1.11"
      }, {
        stickyBucketing: "≥ v0.1.11"
      }]
    },
    edgeFastly: {
      name: "Fastly Compute App & SDK",
      version: "0.2.9",
      github: "https://github.com/growthbook/growthbook-proxy/tree/main/packages/lib/edge-fastly",
      examples: [{
        url: "https://github.com/growthbook/growthbook-proxy/tree/main/packages/lib/edge-fastly/example",
        name: "Example compute worker"
      }],
      packageRepos: [{
        name: "npm",
        url: "https://www.npmjs.com/package/@growthbook/edge-fastly"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        caseInsensitiveRegex: "≥ v0.2.7"
      }, {
        caseInsensitiveMembership: "≥ v0.2.7"
      }, {
        savedGroupReferences: "≥ v0.1.6"
      }, {
        looseUnmarshalling: "≥ v0.1.5"
      }, {
        namespacesV2: "≥ v0.1.5"
      }, {
        encryption: "≥ v0.1.5"
      }, {
        streaming: "≥ v0.1.5"
      }, {
        bucketingV2: "≥ v0.1.5"
      }, {
        visualEditor: "≥ v0.1.5"
      }, {
        semverTargeting: "≥ v0.1.5"
      }, {
        visualEditorJS: "≥ v0.1.5"
      }, {
        visualEditorDragDrop: "≥ v0.1.5"
      }, {
        prerequisites: "≥ v0.1.5"
      }, {
        redirects: "≥ v0.1.5"
      }, {
        stickyBucketing: "≥ v0.1.5"
      }]
    },
    edgeLambda: {
      name: "Lambda@Edge App & SDK",
      version: "0.0.29",
      github: "https://github.com/growthbook/growthbook-proxy/tree/main/packages/lib/edge-lambda",
      examples: [],
      packageRepos: [{
        name: "npm",
        url: "https://www.npmjs.com/package/@growthbook/edge-lambda"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        caseInsensitiveRegex: "≥ v0.0.27"
      }, {
        caseInsensitiveMembership: "≥ v0.0.27"
      }, {
        savedGroupReferences: "≥ v0.0.7"
      }, {
        looseUnmarshalling: "≥ v0.0.6"
      }, {
        namespacesV2: "≥ v0.0.6"
      }, {
        encryption: "≥ v0.0.6"
      }, {
        streaming: "≥ v0.0.6"
      }, {
        bucketingV2: "≥ v0.0.6"
      }, {
        visualEditor: "≥ v0.0.6"
      }, {
        semverTargeting: "≥ v0.0.6"
      }, {
        visualEditorJS: "≥ v0.0.6"
      }, {
        visualEditorDragDrop: "≥ v0.0.6"
      }, {
        prerequisites: "≥ v0.0.6"
      }, {
        redirects: "≥ v0.0.6"
      }, {
        stickyBucketing: "≥ v0.0.6"
      }]
    },
    edgeUtils: {
      name: "Edge Utils",
      version: "0.2.9",
      github: "https://github.com/growthbook/growthbook-proxy/tree/main/packages/lib/edge-utils",
      examples: [],
      packageRepos: [{
        name: "npm",
        url: "https://www.npmjs.com/package/@growthbook/edge-utils"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        caseInsensitiveRegex: "≥ v0.2.7"
      }, {
        caseInsensitiveMembership: "≥ v0.2.7"
      }, {
        savedGroupReferences: "≥ v0.1.5"
      }, {
        looseUnmarshalling: "≥ v0.1.4"
      }, {
        namespacesV2: "≥ v0.1.4"
      }, {
        encryption: "≥ v0.1.4"
      }, {
        streaming: "≥ v0.1.4"
      }, {
        bucketingV2: "≥ v0.1.4"
      }, {
        visualEditor: "≥ v0.1.4"
      }, {
        semverTargeting: "≥ v0.1.4"
      }, {
        visualEditorJS: "≥ v0.1.4"
      }, {
        visualEditorDragDrop: "≥ v0.1.4"
      }, {
        prerequisites: "≥ v0.1.4"
      }, {
        redirects: "≥ v0.1.4"
      }, {
        stickyBucketing: "≥ v0.1.4"
      }]
    },
    flutter: {
      name: "Flutter SDK",
      version: "4.4.0",
      github: "https://github.com/growthbook/growthbook-flutter",
      examples: [],
      packageRepos: [{
        name: "pub.dev",
        url: "https://pub.dev/packages/growthbook_sdk_flutter"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        trackingPlugin: "≥ v4.4.0"
      }, {
        caseInsensitiveRegex: "≥ v4.3.0"
      }, {
        caseInsensitiveMembership: "≥ v4.3.0"
      }, {
        savedGroupReferences: "≥ v3.9.4"
      }, {
        stickyBucketing: "≥ v3.8.0"
      }, {
        remoteEval: "≥ v3.7.0"
      }, {
        streaming: "≥ v3.4.0"
      }, {
        prerequisites: "≥ v3.2.0"
      }, {
        encryption: "≥ v3.1.0"
      }, {
        bucketingV2: "≥ v3.1.0"
      }, {
        semverTargeting: "≥ v3.1.0"
      }, {
        looseUnmarshalling: "≥ v0.0.0"
      }, {
        namespacesV2: "≥ v0.0.0"
      }]
    },
    roku: {
      name: "Roku SDK",
      version: "1.4.1",
      github: "https://github.com/growthbook/growthbook-roku",
      examples: [{
        url: "https://github.com/growthbook/growthbook-roku/tree/main/examples",
        name: "Roku examples"
      }, {
        url: "https://www.npmjs.com/package/growthbook-roku",
        name: "npm package"
      }],
      packageRepos: [],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        encryption: "≥ v1.4.1"
      }, {
        stickyBucketing: "≥ v1.4.1"
      }, {
        prerequisites: "≥ v1.3.0"
      }, {
        looseUnmarshalling: "≥ v1.3.0"
      }, {
        namespacesV2: "≥ v1.3.0"
      }, {
        semverTargeting: "≥ v1.3.0"
      }, {
        bucketingV2: "≥ v1.3.0"
      }]
    }
  };
  const capabilityDetails = {
    features: {
      label: "Features",
      icon: () => <svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
          <path d="M42.76,50A8,8,0,0,0,40,56V224a8,8,0,0,0,16,0V179.77c26.79-21.16,49.87-9.75,76.45,3.41,16.4,8.11,34.06,16.85,53,16.85,13.93,0,28.54-4.75,43.82-18a8,8,0,0,0,2.76-6V56A8,8,0,0,0,218.76,50c-28,24.23-51.72,12.49-79.21-1.12C111.07,34.76,78.78,18.79,42.76,50ZM216,172.25c-26.79,21.16-49.87,9.74-76.45-3.41-25-12.35-52.81-26.13-83.55-8.4V59.79c26.79-21.16,49.87-9.75,76.45,3.4,25,12.35,52.82,26.13,83.55,8.4Z" />
        </svg>
    },
    experimentation: {
      label: "Experimentation",
      icon: () => <svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
          <path d="M221.69,199.77,160,96.92V40h8a8,8,0,0,0,0-16H88a8,8,0,0,0,0,16h8V96.92L34.31,199.77A16,16,0,0,0,48,224H208a16,16,0,0,0,13.72-24.23ZM110.86,103.25A7.93,7.93,0,0,0,112,99.14V40h32V99.14a7.93,7.93,0,0,0,1.14,4.11L183.36,167c-12,2.37-29.07,1.37-51.75-10.11-15.91-8.05-31.05-12.32-45.22-12.81ZM48,208l28.54-47.58c14.25-1.74,30.31,1.85,47.82,10.72,19,9.61,35,12.88,48,12.88a69.89,69.89,0,0,0,19.55-2.7L208,208Z" />
        </svg>
    },
    encryption: {
      label: "Encrypted Features",
      icon: () => <svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
          <path d="M208,80H176V56a48,48,0,0,0-96,0V80H48A16,16,0,0,0,32,96V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V96A16,16,0,0,0,208,80ZM96,56a32,32,0,0,1,64,0V80H96ZM208,208H48V96H208V208Zm-68-56a12,12,0,1,1-12-12A12,12,0,0,1,140,152Z" />
        </svg>
    },
    streaming: {
      label: "Streaming",
      icon: () => <svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
          <path d="M135.16,84.42a8,8,0,0,0-14.32,0l-72,144a8,8,0,0,0,14.31,7.16L77,208h102.1l13.79,27.58A8,8,0,0,0,200,240a8,8,0,0,0,7.15-11.58ZM128,105.89,155.06,160H100.94ZM85,192l8-16h70.1l8,16Zm74.54-98.26a32,32,0,1,0-63,0,8,8,0,1,1-15.74,2.85,48,48,0,1,1,94.46,0,8,8,0,0,1-7.86,6.58,8.74,8.74,0,0,1-1.43-.13A8,8,0,0,1,159.49,93.74ZM64.15,136.21a80,80,0,1,1,127.7,0,8,8,0,0,1-12.76-9.65,64,64,0,1,0-102.18,0,8,8,0,0,1-12.76,9.65Z" />
        </svg>
    },
    bucketingV2: {
      label: "v2 Hashing",
      icon: () => <svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
          <path d="M224,88H175.4l8.47-46.57a8,8,0,0,0-15.74-2.86l-9,49.43H111.4l8.47-46.57a8,8,0,0,0-15.74-2.86L95.14,88H48a8,8,0,0,0,0,16H92.23L83.5,152H32a8,8,0,0,0,0,16H80.6l-8.47,46.57a8,8,0,0,0,6.44,9.3A7.79,7.79,0,0,0,80,224a8,8,0,0,0,7.86-6.57l9-49.43H144.6l-8.47,46.57a8,8,0,0,0,6.44,9.3A7.79,7.79,0,0,0,144,224a8,8,0,0,0,7.86-6.57l9-49.43H208a8,8,0,0,0,0-16H163.77l8.73-48H224a8,8,0,0,0,0-16Zm-76.5,64H99.77l8.73-48h47.73Z" />
        </svg>
    },
    visualEditor: {
      label: "Visual Editor",
      icon: () => <svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
          <path d="M208,40H48A24,24,0,0,0,24,64V176a24,24,0,0,0,24,24H208a24,24,0,0,0,24-24V64A24,24,0,0,0,208,40Zm8,136a8,8,0,0,1-8,8H48a8,8,0,0,1-8-8V64a8,8,0,0,1,8-8H208a8,8,0,0,1,8,8Zm-48,48a8,8,0,0,1-8,8H96a8,8,0,0,1,0-16h64A8,8,0,0,1,168,224Z" />
        </svg>
    },
    semverTargeting: {
      label: "SemVer Targeting",
      icon: () => <svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
          <path d="M208,112a32.05,32.05,0,0,0-30.69,23l-42.21-6a8,8,0,0,1-4.95-2.71L94.43,84.55A32,32,0,1,0,72,87v82a32,32,0,1,0,16,0V101.63l30,35a24,24,0,0,0,14.83,8.14l44,6.28A32,32,0,1,0,208,112ZM64,56A16,16,0,1,1,80,72,16,16,0,0,1,64,56ZM96,200a16,16,0,1,1-16-16A16,16,0,0,1,96,200Zm112-40a16,16,0,1,1,16-16A16,16,0,0,1,208,160Z" />
        </svg>
    },
    visualEditorJS: {
      label: "Visual Editor (JS)",
      icon: () => <svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
          <path d="M213.66,82.34l-56-56A8,8,0,0,0,152,24H56A16,16,0,0,0,40,40v72a8,8,0,0,0,16,0V40h88V88a8,8,0,0,0,8,8h48V216H176a8,8,0,0,0,0,16h24a16,16,0,0,0,16-16V88A8,8,0,0,0,213.66,82.34ZM160,51.31,188.69,80H160Zm-12.19,145a20.82,20.82,0,0,1-9.19,15.23C133.43,215,127,216,121.13,216a61.34,61.34,0,0,1-15.19-2,8,8,0,0,1,4.31-15.41c4.38,1.2,15,2.7,19.55-.36.88-.59,1.83-1.52,2.14-3.93.34-2.67-.71-4.1-12.78-7.59-9.35-2.7-25-7.23-23-23.11a20.56,20.56,0,0,1,9-14.95c11.84-8,30.71-3.31,32.83-2.76a8,8,0,0,1-4.07,15.48c-4.49-1.17-15.23-2.56-19.83.56a4.54,4.54,0,0,0-2,3.67c-.12.9-.14,1.09,1.11,1.9,2.31,1.49,6.45,2.68,10.45,3.84C133.49,174.17,150.05,179,147.81,196.31ZM80,152v38a26,26,0,0,1-52,0,8,8,0,0,1,16,0,10,10,0,0,0,20,0V152a8,8,0,0,1,16,0Z" />
        </svg>
    },
    remoteEval: {
      label: "Remote Evaluation",
      icon: () => <svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
          <path d="M160,40A88.09,88.09,0,0,0,81.29,88.67,64,64,0,1,0,72,216h88a88,88,0,0,0,0-176Zm0,160H72a48,48,0,0,1,0-96c1.1,0,2.2,0,3.29.11A88,88,0,0,0,72,128a8,8,0,0,0,16,0,72,72,0,1,1,72,72Z" />
        </svg>
    },
    visualEditorDragDrop: {
      label: "Visual Editor Drag & Drop",
      icon: () => <svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
          <path d="M188,80a27.79,27.79,0,0,0-13.36,3.4,28,28,0,0,0-46.64-11A28,28,0,0,0,80,92v20H68a28,28,0,0,0-28,28v12a88,88,0,0,0,176,0V108A28,28,0,0,0,188,80Zm12,72a72,72,0,0,1-144,0V140a12,12,0,0,1,12-12H80v24a8,8,0,0,0,16,0V92a12,12,0,0,1,24,0v28a8,8,0,0,0,16,0V92a12,12,0,0,1,24,0v28a8,8,0,0,0,16,0V108a12,12,0,0,1,24,0Z" />
        </svg>
    },
    stickyBucketing: {
      label: "Sticky Bucketing",
      icon: () => <svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
          <path d="M223.68,66.15,135.68,18h0a15.88,15.88,0,0,0-15.36,0l-88,48.17a16,16,0,0,0-8.32,14v95.64a16,16,0,0,0,8.32,14l88,48.17a15.88,15.88,0,0,0,15.36,0l88-48.17a16,16,0,0,0,8.32-14V80.18A16,16,0,0,0,223.68,66.15ZM128,32h0l80.34,44L128,120,47.66,76ZM40,90l80,43.78v85.79L40,175.82Zm96,129.57V133.82L216,90v85.78Z" />
        </svg>
    },
    redirects: {
      label: "URL Redirects",
      icon: () => <svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
          <path d="M240,88.23a54.43,54.43,0,0,1-16,37L189.25,160a54.27,54.27,0,0,1-38.63,16h-.05A54.63,54.63,0,0,1,96,119.84a8,8,0,0,1,16,.45A38.62,38.62,0,0,0,150.58,160h0a38.39,38.39,0,0,0,27.31-11.31l34.75-34.75a38.63,38.63,0,0,0-54.63-54.63l-11,11A8,8,0,0,1,135.7,59l11-11A54.65,54.65,0,0,1,224,48,54.86,54.86,0,0,1,240,88.23ZM109,185.66l-11,11A38.41,38.41,0,0,1,70.6,208h0a38.63,38.63,0,0,1-27.29-65.94L78,107.31A38.63,38.63,0,0,1,144,135.71a8,8,0,0,0,16,.45A54.86,54.86,0,0,0,144,96a54.65,54.65,0,0,0-77.27,0L32,130.75A54.62,54.62,0,0,0,70.56,224h0a54.28,54.28,0,0,0,38.64-16l11-11A8,8,0,0,0,109,185.66Z" />
        </svg>
    },
    prerequisites: {
      label: "Prerequisites",
      icon: () => <svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
          <path d="M176,152h32a16,16,0,0,0,16-16V104a16,16,0,0,0-16-16H176a16,16,0,0,0-16,16v8H88V80h8a16,16,0,0,0,16-16V32A16,16,0,0,0,96,16H64A16,16,0,0,0,48,32V64A16,16,0,0,0,64,80h8V192a24,24,0,0,0,24,24h64v8a16,16,0,0,0,16,16h32a16,16,0,0,0,16-16V192a16,16,0,0,0-16-16H176a16,16,0,0,0-16,16v8H96a8,8,0,0,1-8-8V128h72v8A16,16,0,0,0,176,152ZM64,32H96V64H64ZM176,192h32v32H176Zm0-88h32v32H176Z" />
        </svg>
    },
    savedGroupReferences: {
      label: "Saved Group References",
      icon: () => <svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
          <path d="M88,64a8,8,0,0,1,8-8H216a8,8,0,0,1,0,16H96A8,8,0,0,1,88,64Zm128,56H96a8,8,0,0,0,0,16H216a8,8,0,0,0,0-16Zm0,64H96a8,8,0,0,0,0,16H216a8,8,0,0,0,0-16ZM56,56H40a8,8,0,0,0,0,16H56a8,8,0,0,0,0-16Zm0,64H40a8,8,0,0,0,0,16H56a8,8,0,0,0,0-16Zm0,64H40a8,8,0,0,0,0,16H56a8,8,0,0,0,0-16Z" />
        </svg>
    },
    caseInsensitiveRegex: {
      label: "Case Insensitive Regex",
      icon: () => <svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
          <path d="M87.24,52.59a8,8,0,0,0-14.48,0l-64,136a8,8,0,1,0,14.48,6.81L39.9,160h80.2l16.66,35.4a8,8,0,1,0,14.48-6.81ZM47.43,144,80,74.79,112.57,144ZM200,96c-12.76,0-22.73,3.47-29.63,10.32a8,8,0,0,0,11.26,11.36c3.8-3.77,10-5.68,18.37-5.68,13.23,0,24,9,24,20v3.22A42.76,42.76,0,0,0,200,128c-22.06,0-40,16.15-40,36s17.94,36,40,36a42.73,42.73,0,0,0,24-7.25,8,8,0,0,0,16-.75V132C240,112.15,222.06,96,200,96Zm0,88c-13.23,0-24-9-24-20s10.77-20,24-20,24,9,24,20S213.23,184,200,184Z" />
        </svg>
    },
    caseInsensitiveMembership: {
      label: "Case Insensitive Membership",
      icon: () => <svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
          <path d="M174.63,81.37a80,80,0,1,0-93.26,93.26,80,80,0,1,0,93.26-93.26ZM224,160c0,1.52-.07,3-.18,4.51l-50-50A80,80,0,0,0,176,98,64.11,64.11,0,0,1,224,160Zm-13.47,39.21L157.91,146.6a80.5,80.5,0,0,0,9.93-15.44L219.7,183A64,64,0,0,1,210.53,199.21ZM183,219.7l-51.86-51.86a80.5,80.5,0,0,0,15.44-9.93l52.61,52.62A64,64,0,0,1,183,219.7ZM45.47,56.79,98.09,109.4a80.5,80.5,0,0,0-9.93,15.44L36.3,73A64,64,0,0,1,45.47,56.79ZM73,36.3l51.86,51.86a80.5,80.5,0,0,0-15.44,9.93L56.79,45.47A64,64,0,0,1,73,36.3ZM160,96a64.07,64.07,0,0,1-64,64A64.07,64.07,0,0,1,160,96Zm-2-16a80,80,0,0,0-16.49,2.13l-50-50C93,32.07,94.48,32,96,32A64.11,64.11,0,0,1,158,80.05ZM32,96c0-1.52.07-3,.18-4.51l50,50A80,80,0,0,0,80.05,158,64.11,64.11,0,0,1,32,96ZM98,176a80,80,0,0,0,16.49-2.13l50,50c-1.49.11-3,.18-4.51.18A64.11,64.11,0,0,1,98,176Z" />
        </svg>
    },
    contextualBandits: {
      label: "Contextual Bandits",
      icon: () => <svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
          <path d="M117.25,157.92a60,60,0,1,0-66.5,0A95.83,95.83,0,0,0,3.53,195.63a8,8,0,1,0,13.4,8.74,80,80,0,0,1,134.14,0,8,8,0,0,0,13.4-8.74A95.83,95.83,0,0,0,117.25,157.92ZM40,108a44,44,0,1,1,44,44A44.05,44.05,0,0,1,40,108Zm210.14,98.23a8,8,0,0,1-11.07-2.33A79.83,79.83,0,0,0,172,168a8,8,0,0,1,0-16,44,44,0,1,0-16.34-84.87,8,8,0,1,1-5.94-14.85,60,60,0,0,1,55.53,105.64,95.83,95.83,0,0,1,47.22,31.95A8,8,0,0,1,250.14,206.23Z" />
        </svg>
    },
    trackingPlugin: {
      label: "Tracking Plugin",
      icon: () => <svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
          <path d="M240,128a8,8,0,0,1-8,8H204.94l-37.78,75.58A8,8,0,0,1,160,216h-.4a8,8,0,0,1-7.08-5.14L95.35,60.76,63.28,131.31A8,8,0,0,1,56,136H24a8,8,0,0,1,0-16H50.46L88.62,36.69a8,8,0,0,1,14.76.46L160.46,187,187.06,136H232A8,8,0,0,1,240,128Z" />
        </svg>
    }
  };
  const capabilities = (sdkInfo[sdk].capabilities || []).filter(cap => {
    const feature = Object.keys(cap)[0];
    return !cap.looseUnmarshalling && capabilityDetails[feature];
  }).map(cap => {
    const feature = Object.keys(cap)[0];
    return {
      feature,
      version: cap[feature]
    };
  });
  return <div className="flex flex-row flex-wrap gap-[10px] mb-4">
      {capabilities.map(({feature, version}) => <div key={feature} className="inline-flex flex-row gap-[6px] items-center bg-[var(--slate-a3)] rounded-full px-3 h-7 text-[14px] leading-none dark:text-[#f5f7f5]">
          <span className="inline-flex items-center justify-center w-4 h-4 shrink-0 [&_svg]:w-full [&_svg]:h-full [&_svg]:fill-current">
            {capabilityDetails[feature].icon()}
          </span>
          <span className="group relative cursor-pointer">
            {capabilityDetails[feature].label}
            <span className="invisible opacity-0 transition-opacity duration-200 group-hover:visible group-hover:opacity-100 absolute bottom-[calc(100%+6px)] left-1/2 -translate-x-1/2 w-max max-w-[220px] bg-[#444] text-white text-[13px] text-center rounded px-[10px] py-[6px] z-10 pointer-events-none group-hover:pointer-events-auto shadow-md after:content-[''] after:absolute after:top-full after:left-1/2 after:-translate-x-1/2 after:border-[6px] after:border-solid after:border-transparent after:border-t-[#444]">
              {version}
            </span>
          </span>
        </div>)}
    </div>;
};

export const SdkResources = ({sdk}) => {
  const GitHubLogo = () => {
    return <svg viewBox="0 0 128 128">
        <g fill="currentColor">
          <path fillRule="evenodd" clipRule="evenodd" d="M64 5.103c-33.347 0-60.388 27.035-60.388 60.388 0 26.682 17.303 49.317 41.297 57.303 3.017.56 4.125-1.31 4.125-2.905 0-1.44-.056-6.197-.082-11.243-16.8 3.653-20.345-7.125-20.345-7.125-2.747-6.98-6.705-8.836-6.705-8.836-5.48-3.748.413-3.67.413-3.67 6.063.425 9.257 6.223 9.257 6.223 5.386 9.23 14.127 6.562 17.573 5.02.542-3.903 2.107-6.568 3.834-8.076-13.413-1.525-27.514-6.704-27.514-29.843 0-6.593 2.36-11.98 6.223-16.21-.628-1.52-2.695-7.662.584-15.98 0 0 5.07-1.623 16.61 6.19C53.7 35 58.867 34.327 64 34.304c5.13.023 10.3.694 15.127 2.033 11.526-7.813 16.59-6.19 16.59-6.19 3.287 8.317 1.22 14.46.593 15.98 3.872 4.23 6.215 9.617 6.215 16.21 0 23.194-14.127 28.3-27.574 29.796 2.167 1.874 4.097 5.55 4.097 11.183 0 8.08-.07 14.583-.07 16.572 0 1.607 1.088 3.49 4.148 2.897 23.98-7.994 41.263-30.622 41.263-57.294C124.388 32.14 97.35 5.104 64 5.104z"></path>
          <path d="M26.484 91.806c-.133.3-.605.39-1.035.185-.44-.196-.685-.605-.543-.906.13-.31.603-.395 1.04-.188.44.197.69.61.537.91zm2.446 2.729c-.287.267-.85.143-1.232-.28-.396-.42-.47-.983-.177-1.254.298-.266.844-.14 1.24.28.394.426.472.984.17 1.255zM31.312 98.012c-.37.258-.976.017-1.35-.52-.37-.538-.37-1.183.01-1.44.373-.258.97-.025 1.35.507.368.545.368 1.19-.01 1.452zm3.261 3.361c-.33.365-1.036.267-1.552-.23-.527-.487-.674-1.18-.343-1.544.336-.366 1.045-.264 1.564.23.527.486.686 1.18.333 1.543zm4.5 1.951c-.147.473-.825.688-1.51.486-.683-.207-1.13-.76-.99-1.238.14-.477.823-.7 1.512-.485.683.206 1.13.756.988 1.237zm4.943.361c.017.498-.563.91-1.28.92-.723.017-1.308-.387-1.315-.877 0-.503.568-.91 1.29-.924.717-.013 1.306.387 1.306.88zm4.598-.782c.086.485-.413.984-1.126 1.117-.7.13-1.35-.172-1.44-.653-.086-.498.422-.997 1.122-1.126.714-.123 1.354.17 1.444.663zm0 0"></path>
        </g>
      </svg>;
  };
  const SlackLogo = () => {
    return <svg viewBox="0 0 128 128">
        <path d="M27.255 80.719c0 7.33-5.978 13.317-13.309 13.317C6.616 94.036.63 88.049.63 80.719s5.987-13.317 13.317-13.317h13.309zm6.709 0c0-7.33 5.987-13.317 13.317-13.317s13.317 5.986 13.317 13.317v33.335c0 7.33-5.986 13.317-13.317 13.317-7.33 0-13.317-5.987-13.317-13.317zm0 0" fill="#de1c59"></path>
        <path d="M47.281 27.255c-7.33 0-13.317-5.978-13.317-13.309C33.964 6.616 39.951.63 47.281.63s13.317 5.987 13.317 13.317v13.309zm0 6.709c7.33 0 13.317 5.987 13.317 13.317s-5.986 13.317-13.317 13.317H13.946C6.616 60.598.63 54.612.63 47.281c0-7.33 5.987-13.317 13.317-13.317zm0 0" fill="#35c5f0"></path>
        <path d="M100.745 47.281c0-7.33 5.978-13.317 13.309-13.317 7.33 0 13.317 5.987 13.317 13.317s-5.987 13.317-13.317 13.317h-13.309zm-6.709 0c0 7.33-5.987 13.317-13.317 13.317s-13.317-5.986-13.317-13.317V13.946C67.402 6.616 73.388.63 80.719.63c7.33 0 13.317 5.987 13.317 13.317zm0 0" fill="#2eb57d"></path>
        <path d="M80.719 100.745c7.33 0 13.317 5.978 13.317 13.309 0 7.33-5.987 13.317-13.317 13.317s-13.317-5.987-13.317-13.317v-13.309zm0-6.709c-7.33 0-13.317-5.987-13.317-13.317s5.986-13.317 13.317-13.317h33.335c7.33 0 13.317 5.986 13.317 13.317 0 7.33-5.987 13.317-13.317 13.317zm0 0" fill="#ebb02e"></path>
      </svg>;
  };
  const CodeLogos = ({name}) => {
    switch (name) {
      case "js":
        return <svg viewBox="0 0 128 128">
            <path fill="#F0DB4F" d="M1.408 1.408h125.184v125.185H1.408z"></path>
            <path fill="#323330" d="M116.347 96.736c-.917-5.711-4.641-10.508-15.672-14.981-3.832-1.761-8.104-3.022-9.377-5.926-.452-1.69-.512-2.642-.226-3.665.821-3.32 4.784-4.355 7.925-3.403 2.023.678 3.938 2.237 5.093 4.724 5.402-3.498 5.391-3.475 9.163-5.879-1.381-2.141-2.118-3.129-3.022-4.045-3.249-3.629-7.676-5.498-14.756-5.355l-3.688.477c-3.534.893-6.902 2.748-8.877 5.235-5.926 6.724-4.236 18.492 2.975 23.335 7.104 5.332 17.54 6.545 18.873 11.531 1.297 6.104-4.486 8.08-10.234 7.378-4.236-.881-6.592-3.034-9.139-6.949-4.688 2.713-4.688 2.713-9.508 5.485 1.143 2.499 2.344 3.63 4.26 5.795 9.068 9.198 31.76 8.746 35.83-5.176.165-.478 1.261-3.666.38-8.581zM69.462 58.943H57.753l-.048 30.272c0 6.438.333 12.34-.714 14.149-1.713 3.558-6.152 3.117-8.175 2.427-2.059-1.012-3.106-2.451-4.319-4.485-.333-.584-.583-1.036-.667-1.071l-9.52 5.83c1.583 3.249 3.915 6.069 6.902 7.901 4.462 2.678 10.459 3.499 16.731 2.059 4.082-1.189 7.604-3.652 9.448-7.401 2.666-4.915 2.094-10.864 2.07-17.444.06-10.735.001-21.468.001-32.237z"></path>
          </svg>;
      case "react":
      case "reactNative":
        return <svg viewBox="0 0 128 128">
            <g fill="#61DAFB">
              <circle cx="64" cy="64" r="11.4"></circle>
              <path d="M107.3 45.2c-2.2-.8-4.5-1.6-6.9-2.3.6-2.4 1.1-4.8 1.5-7.1 2.1-13.2-.2-22.5-6.6-26.1-1.9-1.1-4-1.6-6.4-1.6-7 0-15.9 5.2-24.9 13.9-9-8.7-17.9-13.9-24.9-13.9-2.4 0-4.5.5-6.4 1.6-6.4 3.7-8.7 13-6.6 26.1.4 2.3.9 4.7 1.5 7.1-2.4.7-4.7 1.4-6.9 2.3C8.2 50 1.4 56.6 1.4 64s6.9 14 19.3 18.8c2.2.8 4.5 1.6 6.9 2.3-.6 2.4-1.1 4.8-1.5 7.1-2.1 13.2.2 22.5 6.6 26.1 1.9 1.1 4 1.6 6.4 1.6 7.1 0 16-5.2 24.9-13.9 9 8.7 17.9 13.9 24.9 13.9 2.4 0 4.5-.5 6.4-1.6 6.4-3.7 8.7-13 6.6-26.1-.4-2.3-.9-4.7-1.5-7.1 2.4-.7 4.7-1.4 6.9-2.3 12.5-4.8 19.3-11.4 19.3-18.8s-6.8-14-19.3-18.8zM92.5 14.7c4.1 2.4 5.5 9.8 3.8 20.3-.3 2.1-.8 4.3-1.4 6.6-5.2-1.2-10.7-2-16.5-2.5-3.4-4.8-6.9-9.1-10.4-13 7.4-7.3 14.9-12.3 21-12.3 1.3 0 2.5.3 3.5.9zM81.3 74c-1.8 3.2-3.9 6.4-6.1 9.6-3.7.3-7.4.4-11.2.4-3.9 0-7.6-.1-11.2-.4-2.2-3.2-4.2-6.4-6-9.6-1.9-3.3-3.7-6.7-5.3-10 1.6-3.3 3.4-6.7 5.3-10 1.8-3.2 3.9-6.4 6.1-9.6 3.7-.3 7.4-.4 11.2-.4 3.9 0 7.6.1 11.2.4 2.2 3.2 4.2 6.4 6 9.6 1.9 3.3 3.7 6.7 5.3 10-1.7 3.3-3.4 6.6-5.3 10zm8.3-3.3c1.5 3.5 2.7 6.9 3.8 10.3-3.4.8-7 1.4-10.8 1.9 1.2-1.9 2.5-3.9 3.6-6 1.2-2.1 2.3-4.2 3.4-6.2zM64 97.8c-2.4-2.6-4.7-5.4-6.9-8.3 2.3.1 4.6.2 6.9.2 2.3 0 4.6-.1 6.9-.2-2.2 2.9-4.5 5.7-6.9 8.3zm-18.6-15c-3.8-.5-7.4-1.1-10.8-1.9 1.1-3.3 2.3-6.8 3.8-10.3 1.1 2 2.2 4.1 3.4 6.1 1.2 2.2 2.4 4.1 3.6 6.1zm-7-25.5c-1.5-3.5-2.7-6.9-3.8-10.3 3.4-.8 7-1.4 10.8-1.9-1.2 1.9-2.5 3.9-3.6 6-1.2 2.1-2.3 4.2-3.4 6.2zM64 30.2c2.4 2.6 4.7 5.4 6.9 8.3-2.3-.1-4.6-.2-6.9-.2-2.3 0-4.6.1-6.9.2 2.2-2.9 4.5-5.7 6.9-8.3zm22.2 21l-3.6-6c3.8.5 7.4 1.1 10.8 1.9-1.1 3.3-2.3 6.8-3.8 10.3-1.1-2.1-2.2-4.2-3.4-6.2zM31.7 35c-1.7-10.5-.3-17.9 3.8-20.3 1-.6 2.2-.9 3.5-.9 6 0 13.5 4.9 21 12.3-3.5 3.8-7 8.2-10.4 13-5.8.5-11.3 1.4-16.5 2.5-.6-2.3-1-4.5-1.4-6.6zM7 64c0-4.7 5.7-9.7 15.7-13.4 2-.8 4.2-1.5 6.4-2.1 1.6 5 3.6 10.3 6 15.6-2.4 5.3-4.5 10.5-6 15.5C15.3 75.6 7 69.6 7 64zm28.5 49.3c-4.1-2.4-5.5-9.8-3.8-20.3.3-2.1.8-4.3 1.4-6.6 5.2 1.2 10.7 2 16.5 2.5 3.4 4.8 6.9 9.1 10.4 13-7.4 7.3-14.9 12.3-21 12.3-1.3 0-2.5-.3-3.5-.9zM96.3 93c1.7 10.5.3 17.9-3.8 20.3-1 .6-2.2.9-3.5.9-6 0-13.5-4.9-21-12.3 3.5-3.8 7-8.2 10.4-13 5.8-.5 11.3-1.4 16.5-2.5.6 2.3 1 4.5 1.4 6.6zm9-15.6c-2 .8-4.2 1.5-6.4 2.1-1.6-5-3.6-10.3-6-15.6 2.4-5.3 4.5-10.5 6-15.5 13.8 4 22.1 10 22.1 15.6 0 4.7-5.8 9.7-15.7 13.4z"></path>
            </g>
          </svg>;
      case "vue":
        return <svg viewBox="0 0 128 128">
            <path d="M0 8.934l49.854.158 14.167 24.47 14.432-24.47L128 8.935l-63.834 110.14zm126.98.637l-24.36.02-38.476 66.053L25.691 9.592.942 9.572l63.211 107.89zm-25.149-.008l-22.745.168-15.053 24.647L49.216 9.73l-22.794-.168 37.731 64.476zm-75.834-.17l23.002.009m-23.002-.01l23.002.01" fill="none"></path>
            <path d="M25.997 9.393l23.002.009L64.035 34.36 79.018 9.404 102 9.398 64.15 75.053z" fill="#35495e"></path>
            <path d="M.91 9.569l25.067-.172 38.15 65.659L101.98 9.401l25.11.026-62.966 108.06z" fill="#41b883"></path>
          </svg>;
      case "nextjs":
        return <svg viewBox="0 0 180 180" color="white">
            <defs>
              <linearGradient gradientUnits="userSpaceOnUse" id=":S2:paint0_linear_408_134" x1="109" x2="144.5" y1="116.5" y2="160.5">
                <stop stopColor="white"></stop>
                <stop offset="1" stopColor="white" stopOpacity="0"></stop>
              </linearGradient>
              <linearGradient gradientUnits="userSpaceOnUse" id=":S2:paint1_linear_408_134" x1="121" x2="120.799" y1="54" y2="106.875">
                <stop stopColor="white"></stop>
                <stop offset="1" stopColor="white" stopOpacity="0"></stop>
              </linearGradient>
            </defs>
            <mask height="180" id=":S2:mask0_408_134" maskUnits="userSpaceOnUse" style={{
          maskType: "alpha"
        }} width="180" x="0" y="0">
              <circle cx="90" cy="90" fill="black" r="90"></circle>
            </mask>
            <g mask="url(#:S2:mask0_408_134)">
              <circle cx="90" cy="90" data-circle="true" fill="black" r="90"></circle>
              <path d="M149.508 157.52L69.142 54H54V125.97H66.1136V69.3836L139.999 164.845C143.333 162.614 146.509 160.165 149.508 157.52Z" fill="url(#:S2:paint0_linear_408_134)"></path>
              <rect fill="url(#:S2:paint1_linear_408_134)" height="72" width="12" x="115" y="54"></rect>
            </g>
          </svg>;
      case "php":
        return <svg viewBox="0 0 128 128">
            <path fill="url(#a)" d="M0 64c0 18.593 28.654 33.667 64 33.667 35.346 0 64-15.074 64-33.667 0-18.593-28.655-33.667-64-33.667C28.654 30.333 0 45.407 0 64Z"></path>
            <path fill="#777bb3" d="M64 95.167c33.965 0 61.5-13.955 61.5-31.167 0-17.214-27.535-31.167-61.5-31.167S2.5 46.786 2.5 64c0 17.212 27.535 31.167 61.5 31.167Z"></path>
            <path d="M34.772 67.864c2.793 0 4.877-.515 6.196-1.53 1.306-1.006 2.207-2.747 2.68-5.175.44-2.27.272-3.854-.5-4.71-.788-.874-2.493-1.317-5.067-1.317h-4.464l-2.473 12.732zM20.173 83.547a.694.694 0 0 1-.68-.828l6.557-33.738a.695.695 0 0 1 .68-.561h14.134c4.442 0 7.748 1.206 9.827 3.585 2.088 2.39 2.734 5.734 1.917 9.935-.333 1.711-.905 3.3-1.7 4.724a15.818 15.818 0 0 1-3.128 3.92c-1.531 1.432-3.264 2.472-5.147 3.083-1.852.604-4.232.91-7.07.91h-5.724l-1.634 8.408a.695.695 0 0 1-.682.562z"></path>
            <path fill="#fff" d="M34.19 55.826h3.891c3.107 0 4.186.682 4.553 1.089.607.674.723 2.097.331 4.112-.439 2.257-1.253 3.858-2.42 4.756-1.194.92-3.138 1.386-5.773 1.386h-2.786l2.205-11.342zm6.674-8.1H26.731a1.39 1.39 0 0 0-1.364 1.123L18.81 82.588a1.39 1.39 0 0 0 1.363 1.653h7.35a1.39 1.39 0 0 0 1.363-1.124l1.525-7.846h5.151c2.912 0 5.364-.318 7.287-.944 1.977-.642 3.796-1.731 5.406-3.237a16.522 16.522 0 0 0 3.259-4.087c.831-1.487 1.429-3.147 1.775-4.931.86-4.423.161-7.964-2.076-10.524-2.216-2.537-5.698-3.823-10.349-3.823zM30.301 68.557h4.471c2.963 0 5.17-.557 6.62-1.675 1.451-1.116 2.428-2.98 2.938-5.591.485-2.508.264-4.277-.665-5.308-.931-1.03-2.791-1.546-5.584-1.546h-5.036l-2.743 14.12m10.563-19.445c4.252 0 7.353 1.117 9.303 3.348 1.95 2.232 2.536 5.347 1.76 9.346-.322 1.648-.863 3.154-1.625 4.518-.764 1.366-1.76 2.614-2.991 3.747-1.468 1.373-3.097 2.352-4.892 2.935-1.794.584-4.08.875-6.857.875h-6.296l-1.743 8.97h-7.35l6.558-33.739h14.133"></path>
            <path d="M69.459 74.577a.694.694 0 0 1-.682-.827l2.9-14.928c.277-1.42.209-2.438-.19-2.87-.245-.263-.979-.704-3.15-.704h-5.256l-3.646 18.768a.695.695 0 0 1-.683.56h-7.29a.695.695 0 0 1-.683-.826l6.558-33.739a.695.695 0 0 1 .682-.561h7.29a.695.695 0 0 1 .683.826L64.41 48.42h5.653c4.307 0 7.227.758 8.928 2.321 1.733 1.593 2.275 4.14 1.608 7.573l-3.051 15.702a.695.695 0 0 1-.682.56h-7.407z"></path>
            <path fill="#fff" d="M65.31 38.755h-7.291a1.39 1.39 0 0 0-1.364 1.124l-6.557 33.738a1.39 1.39 0 0 0 1.363 1.654h7.291a1.39 1.39 0 0 0 1.364-1.124l3.537-18.205h4.682c2.168 0 2.624.463 2.641.484.132.14.305.795.019 2.264l-2.9 14.927a1.39 1.39 0 0 0 1.364 1.654h7.408a1.39 1.39 0 0 0 1.363-1.124l3.051-15.7c.715-3.686.103-6.45-1.82-8.217-1.836-1.686-4.91-2.505-9.398-2.505h-4.81l1.421-7.315a1.39 1.39 0 0 0-1.364-1.655zm0 1.39-1.743 8.968h6.496c4.087 0 6.907.714 8.457 2.14 1.553 1.426 2.017 3.735 1.398 6.93l-3.052 15.699h-7.407l2.901-14.928c.33-1.698.208-2.856-.365-3.474-.573-.617-1.793-.926-3.658-.926h-5.829l-3.756 19.327H51.46l6.558-33.739h7.292z"></path>
            <path d="M92.136 67.864c2.793 0 4.878-.515 6.198-1.53 1.304-1.006 2.206-2.747 2.679-5.175.44-2.27.273-3.854-.5-4.71-.788-.874-2.493-1.317-5.067-1.317h-4.463l-2.475 12.732zM77.54 83.547a.694.694 0 0 1-.682-.828l6.557-33.738a.695.695 0 0 1 .682-.561H98.23c4.442 0 7.748 1.206 9.826 3.585 2.089 2.39 2.734 5.734 1.917 9.935a15.878 15.878 0 0 1-1.699 4.724 15.838 15.838 0 0 1-3.128 3.92c-1.53 1.432-3.265 2.472-5.147 3.083-1.852.604-4.232.91-7.071.91h-5.723l-1.633 8.408a.695.695 0 0 1-.683.562z"></path>
            <path fill="#fff" d="M91.555 55.826h3.891c3.107 0 4.186.682 4.552 1.089.61.674.724 2.097.333 4.112-.44 2.257-1.254 3.858-2.421 4.756-1.195.92-3.139 1.386-5.773 1.386h-2.786l2.204-11.342zm6.674-8.1H84.096a1.39 1.39 0 0 0-1.363 1.123l-6.558 33.739a1.39 1.39 0 0 0 1.364 1.653h7.35a1.39 1.39 0 0 0 1.363-1.124l1.525-7.846h5.15c2.911 0 5.364-.318 7.286-.944 1.978-.642 3.797-1.731 5.408-3.238a16.52 16.52 0 0 0 3.258-4.086c.832-1.487 1.428-3.147 1.775-4.931.86-4.423.162-7.964-2.076-10.524-2.216-2.537-5.697-3.823-10.35-3.823zM87.666 68.557h4.47c2.964 0 5.17-.557 6.622-1.675 1.45-1.116 2.428-2.98 2.936-5.591.487-2.508.266-4.277-.665-5.308-.93-1.03-2.791-1.546-5.583-1.546h-5.035Zm10.563-19.445c4.251 0 7.354 1.117 9.303 3.348 1.95 2.232 2.537 5.347 1.759 9.346-.32 1.648-.862 3.154-1.624 4.518-.763 1.366-1.76 2.614-2.992 3.747-1.467 1.373-3.097 2.352-4.892 2.935-1.793.584-4.078.875-6.856.875h-6.295l-1.745 8.97h-7.35l6.558-33.739h14.133"></path>
            <defs>
              <radialGradient id="a" cx="0" cy="0" r="1" gradientTransform="matrix(84.04136 0 0 84.04136 38.426 42.169)" gradientUnits="userSpaceOnUse">
                <stop stopColor="#AEB2D5"></stop>
                <stop offset=".3" stopColor="#AEB2D5"></stop>
                <stop offset=".75" stopColor="#484C89"></stop>
                <stop offset="1" stopColor="#484C89"></stop>
              </radialGradient>
            </defs>
          </svg>;
      case "node":
        return <svg viewBox="0 0 128 128">
            <path fill="url(#a)" d="M66.958.825a6.07 6.07 0 0 0-6.035 0L11.103 29.76c-1.895 1.072-2.96 3.095-2.96 5.24v57.988c0 2.143 1.183 4.167 2.958 5.24l49.82 28.934a6.07 6.07 0 0 0 6.036 0l49.82-28.935c1.894-1.072 2.958-3.096 2.958-5.24V35c0-2.144-1.183-4.167-2.958-5.24z"></path>
            <path fill="url(#b)" d="M116.897 29.76 66.841.825A8.161 8.161 0 0 0 65.302.23L9.21 96.798a6.251 6.251 0 0 0 1.657 1.43l50.057 28.934c1.42.833 3.076 1.072 4.615.595l52.66-96.925a3.702 3.702 0 0 0-1.302-1.072z"></path>
            <path fill="url(#c)" d="M116.898 98.225c1.42-.833 2.485-2.262 2.958-3.81L65.066.108c-1.42-.238-2.959-.119-4.26.715L11.104 29.639l53.606 98.355c.71-.12 1.54-.358 2.25-.715z"></path>
            <defs>
              <linearGradient id="a" x1="34.513" x2="27.157" y1="15.535" y2="30.448" gradientTransform="translate(-129.242 -73.715) scale(6.18523)" gradientUnits="userSpaceOnUse">
                <stop stopColor="#3F873F"></stop>
                <stop offset=".33" stopColor="#3F8B3D"></stop>
                <stop offset=".637" stopColor="#3E9638"></stop>
                <stop offset=".934" stopColor="#3DA92E"></stop>
                <stop offset="1" stopColor="#3DAE2B"></stop>
              </linearGradient>
              <linearGradient id="b" x1="30.009" x2="50.533" y1="23.359" y2="8.288" gradientTransform="translate(-129.242 -73.715) scale(6.18523)" gradientUnits="userSpaceOnUse">
                <stop offset=".138" stopColor="#3F873F"></stop>
                <stop offset=".402" stopColor="#52A044"></stop>
                <stop offset=".713" stopColor="#64B749"></stop>
                <stop offset=".908" stopColor="#6ABF4B"></stop>
              </linearGradient>
              <linearGradient id="c" x1="21.917" x2="40.555" y1="22.261" y2="22.261" gradientTransform="translate(-129.242 -73.715) scale(6.18523)" gradientUnits="userSpaceOnUse">
                <stop offset=".092" stopColor="#6ABF4B"></stop>
                <stop offset=".287" stopColor="#64B749"></stop>
                <stop offset=".598" stopColor="#52A044"></stop>
                <stop offset=".862" stopColor="#3F873F"></stop>
              </linearGradient>
            </defs>
          </svg>;
      case "ruby":
        return <svg viewBox="0 0 128 128">
            <linearGradient id="ruby-original-a" gradientUnits="userSpaceOnUse" x1="157.08" y1="2382.05" x2="131.682" y2="2426.892" gradientTransform="matrix(1 0 0 -1 -47.5 2517)">
              <stop offset="0" stopColor="#FB7655"></stop>
              <stop offset="0" stopColor="#FB7655"></stop>
              <stop offset=".41" stopColor="#E42B1E"></stop>
              <stop offset=".99" stopColor="#900"></stop>
              <stop offset="1" stopColor="#900"></stop>
            </linearGradient>
            <path fill="url(#ruby-original-a)" d="M97.078 83.214L28.34 124.031l89.003-6.04 6.855-89.745z"></path>
            <linearGradient id="ruby-original-b" gradientUnits="userSpaceOnUse" x1="169.731" y1="2419.72" x2="136.998" y2="2441.685" gradientTransform="matrix(1 0 0 -1 -47.5 2517)">
              <stop offset="0" stopColor="#871101"></stop>
              <stop offset="0" stopColor="#871101"></stop>
              <stop offset=".99" stopColor="#911209"></stop>
              <stop offset="1" stopColor="#911209"></stop>
            </linearGradient>
            <path fill="url(#ruby-original-b)" d="M117.488 117.93l-7.649-52.799-20.837 27.514z"></path>
            <linearGradient id="ruby-original-c" gradientUnits="userSpaceOnUse" x1="143.542" y1="2380.69" x2="110.81" y2="2402.655" gradientTransform="matrix(1 0 0 -1 -47.5 2517)">
              <stop offset="0" stopColor="#871101"></stop>
              <stop offset="0" stopColor="#871101"></stop>
              <stop offset=".99" stopColor="#911209"></stop>
              <stop offset="1" stopColor="#911209"></stop>
            </linearGradient>
            <path fill="url(#ruby-original-c)" d="M117.592 117.93l-56.044-4.399-32.91 10.385z"></path>
            <linearGradient id="ruby-original-d" gradientUnits="userSpaceOnUse" x1="74.817" y1="2435.622" x2="79.891" y2="2402.644" gradientTransform="matrix(1 0 0 -1 -47.5 2517)">
              <stop offset="0" stopColor="#fff"></stop>
              <stop offset="0" stopColor="#fff"></stop>
              <stop offset=".23" stopColor="#E57252"></stop>
              <stop offset=".46" stopColor="#DE3B20"></stop>
              <stop offset=".99" stopColor="#A60003"></stop>
              <stop offset="1" stopColor="#A60003"></stop>
            </linearGradient>
            <path fill="url(#ruby-original-d)" d="M28.717 123.928l14.001-45.867-30.81 6.588z"></path>
            <linearGradient id="ruby-original-e" gradientUnits="userSpaceOnUse" x1="109.719" y1="2466.413" x2="111.589" y2="2432.757" gradientTransform="matrix(1 0 0 -1 -47.5 2517)">
              <stop offset="0" stopColor="#fff"></stop>
              <stop offset="0" stopColor="#fff"></stop>
              <stop offset=".23" stopColor="#E4714E"></stop>
              <stop offset=".56" stopColor="#BE1A0D"></stop>
              <stop offset=".99" stopColor="#A80D00"></stop>
              <stop offset="1" stopColor="#A80D00"></stop>
            </linearGradient>
            <path fill="url(#ruby-original-e)" d="M88.996 92.797l-12.882-50.46-36.866 34.558z"></path>
            <linearGradient id="ruby-original-f" gradientUnits="userSpaceOnUse" x1="140.691" y1="2497.523" x2="146.289" y2="2473.401" gradientTransform="matrix(1 0 0 -1 -47.5 2517)">
              <stop offset="0" stopColor="#fff"></stop>
              <stop offset="0" stopColor="#fff"></stop>
              <stop offset=".18" stopColor="#E46342"></stop>
              <stop offset=".4" stopColor="#C82410"></stop>
              <stop offset=".99" stopColor="#A80D00"></stop>
              <stop offset="1" stopColor="#A80D00"></stop>
            </linearGradient>
            <path fill="url(#ruby-original-f)" d="M121.275 43.047L86.426 14.585l-9.704 31.373z"></path>
            <linearGradient id="ruby-original-g" gradientUnits="userSpaceOnUse" x1="123.6" y1="2506.018" x2="147.719" y2="2518.077" gradientTransform="matrix(1 0 0 -1 -47.5 2517)">
              <stop offset="0" stopColor="#fff"></stop>
              <stop offset="0" stopColor="#fff"></stop>
              <stop offset=".54" stopColor="#C81F11"></stop>
              <stop offset=".99" stopColor="#BF0905"></stop>
              <stop offset="1" stopColor="#BF0905"></stop>
            </linearGradient>
            <path fill="url(#ruby-original-g)" d="M104.978 4.437L84.481 15.764 71.551 4.285z"></path>
            <linearGradient id="ruby-original-h" gradientUnits="userSpaceOnUse" x1="53.674" y1="2444.028" x2="55.66" y2="2424.153" gradientTransform="matrix(1 0 0 -1 -47.5 2517)">
              <stop offset="0" stopColor="#fff"></stop>
              <stop offset="0" stopColor="#fff"></stop>
              <stop offset=".31" stopColor="#DE4024"></stop>
              <stop offset=".99" stopColor="#BF190B"></stop>
              <stop offset="1" stopColor="#BF190B"></stop>
            </linearGradient>
            <path fill="url(#ruby-original-h)" d="M3.802 100.034l8.586-15.659L5.442 65.72z"></path>
            <path fill="#fff" d="M4.981 65.131l6.987 19.821 30.365-6.812L77 45.922l9.783-31.075L71.38 3.969l-26.19 9.802c-8.252 7.675-24.263 22.86-24.84 23.146-.573.291-10.575 19.195-15.369 28.214z"></path>
            <linearGradient id="ruby-original-i" gradientUnits="userSpaceOnUse" x1="40.026" y1="2418.781" x2="133.345" y2="2514.739" gradientTransform="matrix(1 0 0 -1 -47.5 2517)">
              <stop offset="0" stopColor="#BD0012"></stop>
              <stop offset="0" stopColor="#BD0012"></stop>
              <stop offset=".07" stopColor="#fff"></stop>
              <stop offset=".17" stopColor="#fff"></stop>
              <stop offset=".27" stopColor="#C82F1C"></stop>
              <stop offset=".33" stopColor="#820C01"></stop>
              <stop offset=".46" stopColor="#A31601"></stop>
              <stop offset=".72" stopColor="#B31301"></stop>
              <stop offset=".99" stopColor="#E82609"></stop>
              <stop offset="1" stopColor="#E82609"></stop>
            </linearGradient>
            <path fill="url(#ruby-original-i)" d="M29.519 29.521c17.882-17.73 40.937-28.207 49.785-19.28 8.843 8.926-.534 30.62-18.418 48.345-17.884 17.725-40.653 28.779-49.493 19.852-8.849-8.92.242-31.191 18.126-48.917z"></path>
            <linearGradient id="ruby-original-j" gradientUnits="userSpaceOnUse" x1="111.507" y1="2409.102" x2="83.398" y2="2416.039" gradientTransform="matrix(1 0 0 -1 -47.5 2517)">
              <stop offset="0" stopColor="#8C0C01"></stop>
              <stop offset="0" stopColor="#8C0C01"></stop>
              <stop offset=".54" stopColor="#990C00"></stop>
              <stop offset=".99" stopColor="#A80D0E"></stop>
              <stop offset="1" stopColor="#A80D0E"></stop>
            </linearGradient>
            <path fill="url(#ruby-original-j)" d="M28.717 123.909l13.89-46.012 46.135 14.82c-16.68 15.642-35.233 28.865-60.025 31.192z"></path>
            <linearGradient id="ruby-original-k" gradientUnits="userSpaceOnUse" x1="159.785" y1="2442.837" x2="134.814" y2="2465.217" gradientTransform="matrix(1 0 0 -1 -47.5 2517)">
              <stop offset="0" stopColor="#7E110B"></stop>
              <stop offset="0" stopColor="#7E110B"></stop>
              <stop offset=".99" stopColor="#9E0C00"></stop>
              <stop offset="1" stopColor="#9E0C00"></stop>
            </linearGradient>
            <path fill="url(#ruby-original-k)" d="M77.062 45.831l11.844 46.911c13.934-14.65 26.439-30.401 32.563-49.883l-44.407 2.972z"></path>
            <linearGradient id="ruby-original-l" gradientUnits="userSpaceOnUse" x1="168.959" y1="2483.901" x2="156.521" y2="2497.199" gradientTransform="matrix(1 0 0 -1 -47.5 2517)">
              <stop offset="0" stopColor="#79130D"></stop>
              <stop offset="0" stopColor="#79130D"></stop>
              <stop offset=".99" stopColor="#9E120B"></stop>
              <stop offset="1" stopColor="#9E120B"></stop>
            </linearGradient>
            <path fill="url(#ruby-original-l)" d="M121.348 43.097c4.74-14.305 5.833-34.825-16.517-38.635l-18.339 10.13 34.856 28.505z"></path>
            <path fill="#9E1209" d="M3.802 99.828c.656 23.608 17.689 23.959 24.945 24.167l-16.759-39.14-8.186 14.973z"></path>
            <radialGradient id="ruby-original-m" cx="138.703" cy="2464.789" r="30.601" gradientTransform="matrix(1 0 0 -1 -47.5 2517)" gradientUnits="userSpaceOnUse">
              <stop offset="0" stopColor="#A80D00"></stop>
              <stop offset="0" stopColor="#A80D00"></stop>
              <stop offset=".99" stopColor="#7E0E08"></stop>
              <stop offset="1" stopColor="#7E0E08"></stop>
            </radialGradient>
            <path fill="url(#ruby-original-m)" d="M77.128 45.904c10.708 6.581 32.286 19.798 32.723 20.041.68.383 9.304-14.542 11.261-22.976l-43.984 2.935z"></path>
            <radialGradient id="ruby-original-n" cx="96.325" cy="2424.465" r="40.679" gradientTransform="matrix(1 0 0 -1 -47.5 2517)" gradientUnits="userSpaceOnUse">
              <stop offset="0" stopColor="#A30C00"></stop>
              <stop offset="0" stopColor="#A30C00"></stop>
              <stop offset=".99" stopColor="#800E08"></stop>
              <stop offset="1" stopColor="#800E08"></stop>
            </radialGradient>
            <path fill="url(#ruby-original-n)" d="M42.589 77.897l18.57 35.828c10.98-5.955 19.579-13.211 27.454-20.983L42.589 77.897z"></path>
            <linearGradient id="ruby-original-o" gradientUnits="userSpaceOnUse" x1="67.509" y1="2393.115" x2="57.373" y2="2427.506" gradientTransform="matrix(1 0 0 -1 -47.5 2517)">
              <stop offset="0" stopColor="#8B2114"></stop>
              <stop offset="0" stopColor="#8B2114"></stop>
              <stop offset=".43" stopColor="#9E100A"></stop>
              <stop offset=".99" stopColor="#B3100C"></stop>
              <stop offset="1" stopColor="#B3100C"></stop>
            </linearGradient>
            <path fill="url(#ruby-original-o)" d="M11.914 84.904l-2.631 31.331c4.964 6.781 11.794 7.371 18.96 6.842-5.184-12.9-15.538-38.696-16.329-38.173z"></path>
            <linearGradient id="ruby-original-p" gradientUnits="userSpaceOnUse" x1="145.272" y1="2507.076" x2="167.996" y2="2497.045" gradientTransform="matrix(1 0 0 -1 -47.5 2517)">
              <stop offset="0" stopColor="#B31000"></stop>
              <stop offset="0" stopColor="#B31000"></stop>
              <stop offset=".44" stopColor="#910F08"></stop>
              <stop offset=".99" stopColor="#791C12"></stop>
              <stop offset="1" stopColor="#791C12"></stop>
            </linearGradient>
            <path fill="url(#ruby-original-p)" d="M86.384 14.67l36.891 5.177c-1.969-8.343-8.015-13.727-18.32-15.41L86.384 14.67z"></path>
          </svg>;
      case "python":
        return <svg viewBox="0 0 128 128">
            <linearGradient id="python-original-a" gradientUnits="userSpaceOnUse" x1="70.252" y1="1237.476" x2="170.659" y2="1151.089" gradientTransform="matrix(.563 0 0 -.568 -29.215 707.817)">
              <stop offset="0" stopColor="#5A9FD4"></stop>
              <stop offset="1" stopColor="#306998"></stop>
            </linearGradient>
            <linearGradient id="python-original-b" gradientUnits="userSpaceOnUse" x1="209.474" y1="1098.811" x2="173.62" y2="1149.537" gradientTransform="matrix(.563 0 0 -.568 -29.215 707.817)">
              <stop offset="0" stopColor="#FFD43B"></stop>
              <stop offset="1" stopColor="#FFE873"></stop>
            </linearGradient>
            <path fill="url(#python-original-a)" d="M63.391 1.988c-4.222.02-8.252.379-11.8 1.007-10.45 1.846-12.346 5.71-12.346 12.837v9.411h24.693v3.137H29.977c-7.176 0-13.46 4.313-15.426 12.521-2.268 9.405-2.368 15.275 0 25.096 1.755 7.311 5.947 12.519 13.124 12.519h8.491V67.234c0-8.151 7.051-15.34 15.426-15.34h24.665c6.866 0 12.346-5.654 12.346-12.548V15.833c0-6.693-5.646-11.72-12.346-12.837-4.244-.706-8.645-1.027-12.866-1.008zM50.037 9.557c2.55 0 4.634 2.117 4.634 4.721 0 2.593-2.083 4.69-4.634 4.69-2.56 0-4.633-2.097-4.633-4.69-.001-2.604 2.073-4.721 4.633-4.721z" transform="translate(0 10.26)"></path>
            <path fill="url(#python-original-b)" d="M91.682 28.38v10.966c0 8.5-7.208 15.655-15.426 15.655H51.591c-6.756 0-12.346 5.783-12.346 12.549v23.515c0 6.691 5.818 10.628 12.346 12.547 7.816 2.297 15.312 2.713 24.665 0 6.216-1.801 12.346-5.423 12.346-12.547v-9.412H63.938v-3.138h37.012c7.176 0 9.852-5.005 12.348-12.519 2.578-7.735 2.467-15.174 0-25.096-1.774-7.145-5.161-12.521-12.348-12.521h-9.268zM77.809 87.927c2.561 0 4.634 2.097 4.634 4.692 0 2.602-2.074 4.719-4.634 4.719-2.55 0-4.633-2.117-4.633-4.719 0-2.595 2.083-4.692 4.633-4.692z" transform="translate(0 10.26)"></path>
            <radialGradient id="python-original-c" cx="1825.678" cy="444.45" r="26.743" gradientTransform="matrix(0 -.24 -1.055 0 532.979 557.576)" gradientUnits="userSpaceOnUse">
              <stop offset="0" stopColor="#B8B8B8" stopOpacity=".498"></stop>
              <stop offset="1" stopColor="#7F7F7F" stopOpacity="0"></stop>
            </radialGradient>
            <path opacity=".444" fill="url(#python-original-c)" d="M97.309 119.597c0 3.543-14.816 6.416-33.091 6.416-18.276 0-33.092-2.873-33.092-6.416 0-3.544 14.815-6.417 33.092-6.417 18.275 0 33.091 2.872 33.091 6.417z"></path>
          </svg>;
      case "go":
        return <svg viewBox="0 0 128 128">
            <defs>
              <path id="go-original-a" d="M18.8 1h90.5v126H18.8z"></path>
            </defs>
            <clipPath id="go-original-b">
              <use xlinkHref="#go-original-a" overflow="visible"></use>
            </clipPath>
            <path fillRule="evenodd" clipRule="evenodd" fill="#F6D2A2" d="M21.1 68.7c.2 3.5 3.7 1.9 5.3.8 1.5-1.1 2-.2 2.1-2.3.1-1.4.2-2.7.2-4.1-2.3-.2-4.8.3-6.7 1.7-.9.7-2.8 3-.9 3.9" clipPath="url(#go-original-b)"></path>
            <path d="M23 71.2c-.7 0-2-.3-2.2-2.3-.6-.4-.8-.9-.8-1.2-.1-1.2 1.2-2.6 1.9-3.1 1.6-1.2 3.7-1.8 5.9-1.8h1.3v.3c.1 1.1 0 2.2-.1 3.2 0 .3 0 .6-.1.9-.1 1.5-.4 1.7-1.1 2-.3.1-.6.2-1.1.6-.5.3-2.2 1.4-3.7 1.4zm4.8-7.8c-2.1 0-4 .6-5.5 1.7-.7.5-1.7 1.7-1.6 2.5 0 .3.2.6.6.8l.2.1v.2c.1 1.6.9 1.8 1.5 1.8 1 0 2.4-.7 3.3-1.3.6-.4 1-.5 1.3-.6.5-.2.6-.2.7-1.4 0-.3 0-.6.1-.9.1-.9.1-1.9.1-2.8-.3-.1-.5-.1-.7-.1z" clipPath="url(#go-original-b)"></path>
            <path fillRule="evenodd" clipRule="evenodd" fill="#C6B198" d="M21.1 68.7c.5-.2 1.1-.3 1.4-.8" clipPath="url(#go-original-b)"></path>
            <path d="M21.1 69c-.1 0-.3-.1-.3-.2-.1-.2 0-.4.2-.4.1 0 .2-.1.2-.1.4-.2.8-.3 1-.6.1-.1.3-.2.5-.1.1.1.2.3.1.5-.4.5-.9.7-1.3.8l-.2.1h-.2z" clipPath="url(#go-original-b)"></path>
            <path fillRule="evenodd" clipRule="evenodd" fill="#6AD7E5" d="M29.3 26.4c-13.6-3.8-3.5-21.1 7.4-14l-7.4 14z" clipPath="url(#go-original-b)"></path>
            <path d="M29.5 26.8l-.3-.1c-7-2-6.9-7-6.7-8.5.5-3.8 4.1-7.8 8.9-7.8 1.9 0 3.7.6 5.5 1.8l.3.2-7.7 14.4zm1.9-15.7c-4.5 0-7.8 3.7-8.3 7.2-.5 3.6 1.7 6.4 6 7.7l7.1-13.5c-1.5-.9-3.1-1.4-4.8-1.4z" clipPath="url(#go-original-b)"></path>
            <path fillRule="evenodd" clipRule="evenodd" fill="#6AD7E5" d="M89.6 11.1c10.7-7.5 20.5 9.5 8 13.8l-8-13.8z" clipPath="url(#go-original-b)"></path>
            <path d="M97.5 25.3L89.2 11l.3-.2c1.9-1.3 3.8-2 5.7-2 4.6 0 7.9 3.8 8.6 7.5.3 1.5.6 6.6-6 8.8l-.3.2zm-7.4-14l7.7 13.3c3.9-1.4 5.9-4.4 5.3-8-.6-3.4-3.7-6.9-7.9-6.9-1.7-.1-3.4.4-5.1 1.6z" clipPath="url(#go-original-b)"></path>
            <path fillRule="evenodd" clipRule="evenodd" fill="#F6D2A2" d="M92 112.3c2.7 1.7 7.7 6.8 3.6 9.3-3.9 3.6-6.1-4-9.6-5 1.5-2 3.4-3.9 6-4.3" clipPath="url(#go-original-b)"></path>
            <path d="M93.5 122.9c-1.6 0-3-1.6-4.2-3.1-1.1-1.2-2.2-2.5-3.4-2.9l-.5-.1.3-.4c1.2-1.7 3.2-3.9 6.2-4.4h.1l.1.1c1.7 1.1 5.4 4.2 5.3 7.1 0 1.1-.6 2-1.7 2.7-.7.7-1.4 1-2.2 1zm-7-6.5c1.2.5 2.2 1.8 3.2 2.9 1.2 1.5 2.4 2.8 3.7 2.8.6 0 1.2-.3 1.8-.9h.1c.9-.6 1.4-1.3 1.4-2.2 0-2.3-2.9-5.2-4.9-6.5-1.8.5-3.6 1.7-5.3 3.9zm9.1 5.5c-.1 0-.2-.1-.3-.2-.2-.4-.4-.9-.5-1.3-.3-.8-.6-1.6-1.2-2.2-.1-.1-.1-.3 0-.5.1-.1.3-.1.5 0 .7.7 1.1 1.6 1.4 2.5l.5 1.2c.1.2 0 .4-.1.5h-.3z" clipPath="url(#go-original-b)"></path>
            <path fillRule="evenodd" clipRule="evenodd" fill="#F6D2A2" d="M43.2 118.1c-3.2.5-5 3.4-7.7 4.9-2.5 1.5-3.5-.5-3.7-.9-.4-.2-.4.2-1-.4-2.3-3.7 2.4-6.4 4.9-8.2 3.5-.8 5.7 2.2 7.5 4.6" clipPath="url(#go-original-b)"></path>
            <path d="M33.8 123.8c-1.3 0-2-1.1-2.2-1.5h-.1c-.3 0-.5-.1-.9-.5v-.1c-2.2-3.5 1.6-6.2 4.1-8l.9-.6h.2c.4-.1.7-.1 1.1-.1 3 0 4.9 2.6 6.5 4.7l.5.7-.6.1c-1.9.3-3.3 1.5-4.7 2.7-.9.8-1.8 1.5-2.8 2.1-.8.3-1.4.5-2 .5zm-2.2-2.1c.1 0 .2 0 .4.1h.1l.1.1c.2.3.7 1.2 1.7 1.2.5 0 1-.2 1.5-.5 1-.5 1.9-1.3 2.7-2 1.3-1.1 2.7-2.3 4.5-2.8-1.5-2-3.3-4.2-5.8-4.2-.3 0-.6 0-.9.1l-.8.6c-2.6 1.8-5.8 4.1-3.9 7.1.1.2.2.3.4.3zm.2.7c-.2 0-.4-.2-.3-.4.1-1 .6-1.7 1.1-2.5.3-.4.5-.8.7-1.2.1-.2.3-.2.4-.2.2.1.2.3.2.4-.2.5-.5.9-.8 1.3-.5.7-.9 1.3-1 2.1 0 .4-.1.5-.3.5z" clipPath="url(#go-original-b)"></path>
            <path fillRule="evenodd" clipRule="evenodd" d="M29.9 21.7c-1.8-.9-3.1-2.2-2-4.3 1-1.9 2.9-1.7 4.7-.8l-2.7 5.1zm64.9-1.8c1.8-.9 3.1-2.2 2-4.3-1-1.9-2.9-1.7-4.7-.8l2.7 5.1z" clipPath="url(#go-original-b)"></path>
            <path fillRule="evenodd" clipRule="evenodd" fill="#F6D2A2" d="M107.1 68.2c-.2 3.5-3.7 1.9-5.3.8-1.5-1.1-2-.2-2.1-2.3-.1-1.4-.2-2.7-.2-4.1 2.3-.2 4.8.3 6.7 1.7 1 .8 2.8 3 .9 3.9" clipPath="url(#go-original-b)"></path>
            <path d="M105.3 70.7c-1.5 0-3.2-1.1-3.7-1.4-.5-.3-.8-.5-1.1-.6-.8-.3-1-.5-1.1-2 0-.3 0-.6-.1-.9-.1-1-.2-2.1-.1-3.2v-.3h1.3c2.2 0 4.3.6 5.9 1.8.7.5 2 1.9 1.9 3.1 0 .4-.2.9-.8 1.2-.2 2-1.5 2.3-2.2 2.3zM99.8 63c0 .9 0 1.9.1 2.8 0 .3 0 .6.1.9.1 1.2.2 1.2.7 1.4.3.1.7.3 1.3.6.9.6 2.3 1.3 3.3 1.3.6 0 1.4-.2 1.5-1.8V68l.2-.1c.4-.2.6-.4.6-.8.1-.8-.9-2-1.6-2.5-1.5-1.1-3.5-1.7-5.5-1.7-.2.1-.4.1-.7.1z" clipPath="url(#go-original-b)"></path>
            <path fillRule="evenodd" clipRule="evenodd" fill="#C6B198" d="M107.1 68.2c-.5-.2-1.1-.3-1.4-.8" clipPath="url(#go-original-b)"></path>
            <path d="M107.1 68.6h-.1l-.2-.1c-.5-.2-1-.3-1.3-.8-.1-.1-.1-.4.1-.5.1-.1.4-.1.5.1.2.3.6.4 1 .6.1 0 .2.1.2.1.2.1.3.3.2.4-.1.1-.3.2-.4.2z" clipPath="url(#go-original-b)"></path>
            <path fillRule="evenodd" clipRule="evenodd" fill="#6AD7E5" d="M62.8 4c13.6 0 26.3 1.9 33 15 6 14.6 3.8 30.4 4.8 45.9.8 13.3 2.5 28.6-3.6 40.9-6.5 12.9-22.7 16.2-36 15.7-10.5-.4-23.1-3.8-29.1-13.4-6.9-11.2-3.7-27.9-3.2-40.4.6-14.8-4-29.7.9-44.1C34.5 8.5 48.1 5.1 62.8 4" clipPath="url(#go-original-b)"></path>
            <path d="M63.3 121.9h-2.5c-4.1-.1-10.3-.8-16.4-3.3-5.9-2.4-10.2-5.8-13-10.3-5.6-9.1-4.6-21.6-3.7-32.7.2-2.8.4-5.4.5-7.9.2-5.2-.2-10.6-.7-15.7-.8-9.4-1.6-19.1 1.5-28.5 2.4-7 6.7-12 13.2-15.2 5.1-2.5 11.4-3.9 20.4-4.6C76 3.6 89.3 5.5 96 18.8c4.4 10.7 4.4 22.2 4.5 33.3 0 4.2 0 8.5.3 12.7.1 1.3.2 2.6.2 3.9.8 12.2 1.7 26-3.9 37.2-2.8 5.7-7.7 9.9-14.4 12.6-5.4 2.2-12.2 3.4-19.4 3.4zM62.8 4.3c-14.1 1.1-27.9 4.2-33 19.4-3.1 9.3-2.3 18.9-1.5 28.2.4 5.2.9 10.5.7 15.8-.1 2.5-.3 5.1-.5 7.9-.9 11-1.9 23.4 3.6 32.3 2.3 3.7 9.7 12.5 28.8 13.2h2.5c22.1 0 30.3-9.8 33.3-15.6 5.5-11 4.6-24.8 3.9-36.9-.1-1.3-.2-2.6-.2-3.9-.2-4.2-.3-8.5-.3-12.7-.1-11-.1-22.5-4.4-33.1C92.7 13 88.2 9 82 6.7c-6.4-2.1-13.6-2.4-19.2-2.4z" clipPath="url(#go-original-b)"></path>
            <path fillRule="evenodd" clipRule="evenodd" fill="#fff" d="M65.2 22.2c2.4 14.2 25.6 10.4 22.3-3.9-3-12.8-23.1-9.2-22.3 3.9" clipPath="url(#go-original-b)"></path>
            <path d="M76.2 31.5c-4.5 0-10.2-2.4-11.4-9.2-.2-3.2.8-6.1 2.9-8.3 2.3-2.5 5.8-3.9 9.4-3.9 4.2 0 9.2 2.2 10.6 8.3.8 3.4.2 6.4-1.7 8.8-2.1 2.6-5.8 4.3-9.8 4.3zm-10.7-9.3c.5 2.8 1.8 5 3.9 6.6 1.8 1.4 4.3 2.1 6.8 2.1 3.7 0 7.3-1.6 9.3-4.1 1.8-2.2 2.3-5.1 1.6-8.3-1.3-5.7-6-7.7-10-7.7-3.4 0-6.7 1.4-8.9 3.7-1.9 2-2.9 4.7-2.7 7.7z" clipPath="url(#go-original-b)"></path>
            <path fillRule="evenodd" clipRule="evenodd" fill="#fff" d="M37.5 24.5c3.2 12.3 22.9 9.2 22.2-3.2-.9-14.8-25.3-12-22.2 3.2" clipPath="url(#go-original-b)"></path>
            <path d="M48 32.7c-4.3 0-9.3-2.1-10.9-8.1-.7-3.5 0-6.7 2-9.1 2.2-2.7 5.8-4.3 9.7-4.3 5.2 0 10.7 3.1 11.1 10.1.2 2.9-.7 5.5-2.7 7.6-2.1 2.3-5.6 3.8-9.2 3.8zm.8-20.8c-3.7 0-7.1 1.5-9.2 4-1.9 2.3-2.5 5.2-1.8 8.5C39.2 30 44 32 48 32c3.4 0 6.7-1.3 8.8-3.6 1.8-1.9 2.7-4.4 2.5-7.1-.2-4.3-3.1-9.4-10.5-9.4z" clipPath="url(#go-original-b)"></path>
            <path fillRule="evenodd" clipRule="evenodd" fill="#fff" d="M68 39.2c0 1.8.4 3.9.1 5.9-.5.9-1.4 1-2.2 1.3-1.1-.2-2-.9-2.5-1.9-.3-2.2.1-4.4.2-6.6l4.4 1.3z" clipPath="url(#go-original-b)"></path>
            <path d="M65.9 46.8c-1.3-.2-2.3-1-2.8-2.1-.2-1.6-.1-3.1 0-4.6.1-.7.1-1.4.1-2.1v-.4l5.1 1.6v.2c0 .6.1 1.2.1 1.9.1 1.3.2 2.7 0 4v.1c-.4.8-1.1 1-1.8 1.3-.2-.1-.4 0-.7.1zm-2.2-2.4c.4.9 1.2 1.5 2.1 1.7.2-.1.4-.1.5-.2.6-.2 1.1-.4 1.4-.9.2-1.2.1-2.5 0-3.8 0-.6-.1-1.2-.1-1.7l-3.8-1.2c0 .6-.1 1.2-.1 1.7-.1 1.6-.2 3 0 4.4z" clipPath="url(#go-original-b)"></path>
            <path fillRule="evenodd" clipRule="evenodd" d="M46.3 22.5c0 2-1.5 3.6-3.3 3.6-1.8 0-3.3-1.6-3.3-3.6s1.5-3.6 3.3-3.6c1.8 0 3.3 1.6 3.3 3.6" clipPath="url(#go-original-b)"></path>
            <path fillRule="evenodd" clipRule="evenodd" fill="#fff" d="M45.2 23.3c0 .5-.4.9-.8.9s-.8-.4-.8-.9.4-.9.8-.9c.5 0 .8.4.8.9" clipPath="url(#go-original-b)"></path>
            <path fillRule="evenodd" clipRule="evenodd" d="M74.2 21.6c0 2-1.5 3.6-3.3 3.6-1.8 0-3.3-1.6-3.3-3.6s1.5-3.6 3.3-3.6c1.8 0 3.3 1.6 3.3 3.6" clipPath="url(#go-original-b)"></path>
            <path fillRule="evenodd" clipRule="evenodd" fill="#fff" d="M73.2 22.4c0 .5-.3.9-.8.9-.4 0-.8-.4-.8-.9s.3-.9.8-.9c.4 0 .8.4.8.9M58.4 39c-1.5 3.5.8 10.6 4.8 5.4-.3-2.2.1-4.4.2-6.6l-5 1.2z" clipPath="url(#go-original-b)"></path>
            <path d="M60.5 46.6c-.7 0-1.4-.4-1.9-1.2-1.1-1.6-1.3-4.6-.5-6.5l.1-.2 5.5-1.4v.4l-.1 2.2c-.1 1.5-.2 2.9 0 4.4v.1l-.1.1c-1 1.4-2 2.1-3 2.1zm-1.8-7.3c-.6 1.7-.4 4.4.5 5.7.4.6.8.9 1.3.9.7 0 1.5-.6 2.3-1.6-.2-1.5-.1-3 .1-4.4l.1-1.7-4.3 1.1z" clipPath="url(#go-original-b)"></path>
            <path fillRule="evenodd" clipRule="evenodd" fill="#F6D2A2" d="M58.9 32.2c-2.7.2-4.9 3.5-3.5 6 1.9 3.4 6-.3 8.6 0 3 .1 5.4 3.2 7.8.6 2.7-2.9-1.2-5.7-4.1-7l-8.8.4z" clipPath="url(#go-original-b)"></path>
            <path fill="#231F20" d="M69.7 40.2c-.9 0-1.8-.4-2.7-.8-.9-.4-1.9-.8-3-.8h-.3c-.8 0-1.7.3-2.7.7-1.1.4-2.2.7-3.2.7-1.2 0-2.1-.5-2.7-1.6-.7-1.2-.6-2.6.1-3.9.8-1.5 2.2-2.4 3.7-2.6l8.9-.4h.1c2.2.9 4.7 2.6 5.2 4.6.2 1-.1 2-.9 2.9-.8.9-1.6 1.2-2.5 1.2zM64.1 38c1.1 0 2.2.5 3.2.9.9.4 1.7.7 2.5.7.7 0 1.3-.3 1.9-.9.7-.7.9-1.5.8-2.3-.4-1.7-2.8-3.3-4.7-4.1l-8.7.4c-1.3.1-2.5 1-3.2 2.2-.6 1.1-.6 2.3-.1 3.3.5.9 1.1 1.3 2.1 1.3.9 0 1.9-.4 2.9-.7 1.1-.4 2-.7 3-.7 0-.2.1-.2.3-.1z" clipPath="url(#go-original-b)"></path>
            <path fillRule="evenodd" clipRule="evenodd" d="M58.6 32.1c-.2-4.7 8.8-5.3 9.8-1.4 1.1 4-9.4 4.9-9.8 1.4" clipPath="url(#go-original-b)"></path>
          </svg>;
      case "java":
        return <svg viewBox="0 0 128 128">
            <path fill="#0074BD" d="M47.617 98.12s-4.767 2.774 3.397 3.71c9.892 1.13 14.947.968 25.845-1.092 0 0 2.871 1.795 6.873 3.351-24.439 10.47-55.308-.607-36.115-5.969zm-2.988-13.665s-5.348 3.959 2.823 4.805c10.567 1.091 18.91 1.18 33.354-1.6 0 0 1.993 2.025 5.132 3.131-29.542 8.64-62.446.68-41.309-6.336z"></path>
            <path fill="#EA2D2E" d="M69.802 61.271c6.025 6.935-1.58 13.17-1.58 13.17s15.289-7.891 8.269-17.777c-6.559-9.215-11.587-13.792 15.635-29.58 0 .001-42.731 10.67-22.324 34.187z"></path>
            <path fill="#0074BD" d="M102.123 108.229s3.529 2.91-3.888 5.159c-14.102 4.272-58.706 5.56-71.094.171-4.451-1.938 3.899-4.625 6.526-5.192 2.739-.593 4.303-.485 4.303-.485-4.953-3.487-32.013 6.85-13.743 9.815 49.821 8.076 90.817-3.637 77.896-9.468zM49.912 70.294s-22.686 5.389-8.033 7.348c6.188.828 18.518.638 30.011-.326 9.39-.789 18.813-2.474 18.813-2.474s-3.308 1.419-5.704 3.053c-23.042 6.061-67.544 3.238-54.731-2.958 10.832-5.239 19.644-4.643 19.644-4.643zm40.697 22.747c23.421-12.167 12.591-23.86 5.032-22.285-1.848.385-2.677.72-2.677.72s.688-1.079 2-1.543c14.953-5.255 26.451 15.503-4.823 23.725 0-.002.359-.327.468-.617z"></path>
            <path fill="#EA2D2E" d="M76.491 1.587S89.459 14.563 64.188 34.51c-20.266 16.006-4.621 25.13-.007 35.559-11.831-10.673-20.509-20.07-14.688-28.815C58.041 28.42 81.722 22.195 76.491 1.587z"></path>
            <path fill="#0074BD" d="M52.214 126.021c22.476 1.437 57-.8 57.817-11.436 0 0-1.571 4.032-18.577 7.231-19.186 3.612-42.854 3.191-56.887.874 0 .001 2.875 2.381 17.647 3.331z"></path>
          </svg>;
      case "csharp":
        return <svg viewBox="0 0 128 128">
            <path fill="#9B4F96" d="M115.4 30.7L67.1 2.9c-.8-.5-1.9-.7-3.1-.7-1.2 0-2.3.3-3.1.7l-48 27.9c-1.7 1-2.9 3.5-2.9 5.4v55.7c0 1.1.2 2.4 1 3.5l106.8-62c-.6-1.2-1.5-2.1-2.4-2.7z"></path>
            <path fill="#68217A" d="M10.7 95.3c.5.8 1.2 1.5 1.9 1.9l48.2 27.9c.8.5 1.9.7 3.1.7 1.2 0 2.3-.3 3.1-.7l48-27.9c1.7-1 2.9-3.5 2.9-5.4V36.1c0-.9-.1-1.9-.6-2.8l-106.6 62z"></path>
            <path fill="#fff" d="M85.3 76.1C81.1 83.5 73.1 88.5 64 88.5c-13.5 0-24.5-11-24.5-24.5s11-24.5 24.5-24.5c9.1 0 17.1 5 21.3 12.5l13-7.5c-6.8-11.9-19.6-20-34.3-20-21.8 0-39.5 17.7-39.5 39.5s17.7 39.5 39.5 39.5c14.6 0 27.4-8 34.2-19.8l-12.9-7.6zM97 66.2l.9-4.3h-4.2v-4.7h5.1L100 51h4.9l-1.2 6.1h3.8l1.2-6.1h4.8l-1.2 6.1h2.4v4.7h-3.3l-.9 4.3h4.2v4.7h-5.1l-1.2 6h-4.9l1.2-6h-3.8l-1.2 6h-4.8l1.2-6h-2.4v-4.7H97zm4.8 0h3.8l.9-4.3h-3.8l-.9 4.3z"></path>
          </svg>;
      case "rust":
        return <svg viewBox="0 0 128 128">
            <path fill="var(--color-inverse)" d="M62.96.242c-.232.135-1.203 1.528-2.16 3.097-2.4 3.94-2.426 3.942-5.65.55-2.098-2.208-2.605-2.612-3.28-2.607-.44.002-.995.152-1.235.332-.24.18-.916 1.612-1.504 3.183-1.346 3.6-1.41 3.715-2.156 3.86-.46.086-1.343-.407-3.463-1.929-1.565-1.125-3.1-2.045-3.411-2.045-1.291 0-1.655.706-2.27 4.4-.78 4.697-.754 4.681-4.988 2.758-1.71-.776-3.33-1.41-3.603-1.41-.274 0-.792.293-1.15.652-.652.652-.653.655-.475 4.246l.178 3.595-.68.364c-.602.322-1.017.283-3.684-.348-3.48-.822-4.216-.8-4.92.15l-.516.693.692 2.964c.38 1.63.745 3.2.814 3.487.067.287-.05.746-.26 1.02-.348.448-.717.49-3.94.44-5.452-.086-5.761.382-3.51 5.3.718 1.56 1.305 2.98 1.305 3.15 0 .898-.717 1.224-3.794 1.727-1.722.28-3.218.51-3.326.51-.107 0-.43.235-.717.522-.937.936-.671 1.816 1.453 4.814 2.646 3.735 2.642 3.75-1.73 5.421-4.971 1.902-5.072 2.37-1.287 5.96 3.525 3.344 3.53 3.295-.461 5.804C.208 62.8.162 62.846.085 63.876c-.093 1.253-.071 1.275 3.538 3.48 3.57 2.18 3.57 2.246.067 5.56C-.078 76.48.038 77 5.013 78.877c4.347 1.64 4.353 1.66 1.702 5.394-1.502 2.117-1.981 3-1.981 3.653 0 1.223.637 1.535 4.44 2.174 3.206.54 3.92.857 3.92 1.741 0 .182-.588 1.612-1.307 3.177-2.236 4.87-1.981 5.275 3.31 5.275 4.93 0 4.799-.15 3.737 4.294-.8 3.35-.813 3.992-.088 4.715.554.556 1.6.494 4.87-.289 2.499-.596 2.937-.637 3.516-.328l.66.354-.177 3.594c-.178 3.593-.177 3.595.475 4.248.358.36.884.652 1.165.652.282 0 1.903-.63 3.604-1.404 4.22-1.916 4.194-1.932 4.973 2.75.617 3.711.977 4.4 2.294 4.4.327 0 1.83-.88 3.34-1.958 2.654-1.893 3.342-2.19 4.049-1.74.182.115.89 1.67 1.572 3.455 1.003 2.625 1.37 3.31 1.929 3.576 1.062.51 1.72.1 4.218-2.62 3.016-3.286 3.14-3.27 5.602.72 2.72 4.406 3.424 4.396 6.212-.089 2.402-3.864 2.374-3.862 5.621-.47 2.157 2.25 2.616 2.61 3.343 2.61.464 0 1.019-.175 1.23-.388.214-.213.92-1.786 1.568-3.496.649-1.71 1.321-3.2 1.495-3.31.687-.436 1.398-.13 4.048 1.752 1.56 1.108 3.028 1.96 3.377 1.96 1.296 0 1.764-.92 2.302-4.535.46-3.082.554-3.378 1.16-3.685.596-.302.954-.2 3.75 1.07 1.701.77 3.323 1.402 3.604 1.402.282 0 .816-.302 1.184-.672l.672-.67-.184-3.448c-.177-3.29-.16-3.468.364-3.943.54-.488.596-.486 3.615.204 3.656.835 4.338.857 5.025.17.671-.67.664-.818-.254-4.69-1.03-4.346-1.168-4.19 3.78-4.19 3.374 0 3.75-.049 4.18-.523.718-.793.547-1.702-.896-4.779-.729-1.55-1.32-2.96-1.315-3.135.024-.914.743-1.227 4.065-1.767 2.033-.329 3.553-.71 3.829-.96.923-.833.584-1.918-1.523-4.873-2.642-3.703-2.63-3.738 1.599-5.297 5.064-1.866 5.209-2.488 1.419-6.09-3.51-3.335-3.512-3.317.333-5.677 4.648-2.853 4.655-3.496.082-6.335-3.933-2.44-3.93-2.406-.405-5.753 3.78-3.593 3.678-4.063-1.295-5.965-4.388-1.679-4.402-1.72-1.735-5.38 1.588-2.18 1.982-2.903 1.982-3.65 0-1.306-.586-1.598-4.436-2.22-3.216-.52-3.924-.835-3.924-1.75 0-.174.588-1.574 1.307-3.113 1.406-3.013 1.604-4.22.808-4.94-.428-.387-1-.443-4.067-.392-3.208.054-3.618.008-4.063-.439-.486-.488-.48-.557.278-3.725.931-3.88.935-3.975.17-4.694-.777-.73-1.262-.718-4.826.121-2.597.612-3.027.653-3.617.337l-.67-.36.185-3.582.186-3.58-.67-.67c-.369-.37-.891-.67-1.163-.67-.27 0-1.884.64-3.583 1.421-2.838 1.306-3.143 1.393-3.757 1.072-.612-.32-.714-.637-1.237-3.829-.603-3.693-.977-4.412-2.288-4.412-.311 0-1.853.925-3.426 2.055-2.584 1.856-2.93 2.032-3.574 1.807-.533-.186-.843-.59-1.221-1.599-.28-.742-.817-2.172-1.194-3.177-.762-2.028-1.187-2.482-2.328-2.482-.637 0-1.213.458-3.28 2.604-3.25 3.375-3.261 3.374-5.65-.545C66.073 1.78 65.075.382 64.81.24c-.597-.32-1.3-.32-1.85.002m2.96 11.798c2.83 2.014 1.326 6.75-2.144 6.75-3.368 0-5.064-4.057-2.66-6.36 1.358-1.3 3.304-1.459 4.805-.39m-3.558 12.507c1.855.705 2.616.282 6.852-3.8l3.182-3.07 1.347.18c4.225.56 12.627 4.25 17.455 7.666 4.436 3.14 10.332 9.534 12.845 13.93l.537.942-2.38 5.364c-1.31 2.95-2.382 5.673-2.382 6.053 0 .878.576 2.267 1.13 2.726.234.195 2.457 1.265 4.939 2.378l4.51 2.025.178 1.148c.23 1.495.26 5.167.052 6.21l-.163.816h-2.575c-2.987 0-2.756-.267-2.918 3.396-.118 2.656-.76 4.124-2.22 5.075-2.377 1.551-6.304 1.27-7.97-.57-.255-.284-.752-1.705-1.105-3.16-1.03-4.254-2.413-6.64-5.193-8.965-.878-.733-1.595-1.418-1.595-1.522 0-.102.965-.915 2.145-1.803 4.298-3.24 6.77-7.012 7.04-10.747.519-7.126-5.158-13.767-13.602-15.92-2.002-.51-2.857-.526-27.624-.526-14.057 0-25.56-.092-25.56-.204 0-.263 3.125-3.295 4.965-4.816 5.054-4.178 11.618-7.465 18.417-9.22l2.35-.61 3.34 3.387c1.839 1.863 3.64 3.5 4.003 3.637M20.3 46.34c1.539 1.008 2.17 3.54 1.26 5.062-1.405 2.356-4.966 2.455-6.373.178-2.046-3.309 1.895-7.349 5.113-5.24m90.672.13c4.026 2.454.906 8.493-3.404 6.586-2.877-1.273-2.97-5.206-.155-6.64 1.174-.6 2.523-.579 3.56.053M32.163 61.5v15.02h-13.28l-.526-2.285c-1.036-4.5-1.472-9.156-1.211-12.969l.182-2.679 4.565-2.047c2.864-1.283 4.706-2.262 4.943-2.625 1.038-1.584.94-2.715-.518-5.933l-.68-1.502h6.523V61.5M70.39 47.132c2.843.74 4.345 2.245 4.349 4.355.002 1.55-.765 2.52-2.67 3.38-1.348.61-1.562.625-10.063.708l-8.686.084v-8.92h7.782c6.078 0 8.112.086 9.288.393m-2.934 21.554c1.41.392 3.076 1.616 3.93 2.888.898 1.337 1.423 3.076 2.667 8.836 1.05 4.87 1.727 6.46 3.62 8.532 2.345 2.566 1.8 2.466 13.514 2.466 5.61 0 10.198.09 10.198.2 0 .197-3.863 4.764-4.03 4.764-.048 0-2.066-.422-4.484-.939-6.829-1.458-7.075-1.287-8.642 6.032l-1.008 4.702-.91.448c-1.518.75-6.453 2.292-9.01 2.82-4.228.87-8.828 1.162-12.871.821-6.893-.585-16.02-3.259-16.377-4.8-.075-.327-.535-2.443-1.018-4.704-.485-2.26-1.074-4.404-1.31-4.764-1.13-1.724-2.318-1.83-7.547-.674-1.98.44-3.708.796-3.84.796-.248 0-3.923-4.249-3.923-4.535 0-.09 8.728-.194 19.396-.23l19.395-.066.07-6.89c.05-4.865-.018-6.997-.23-7.25-.234-.284-1.485-.358-6.011-.358H53.32v-8.36l6.597.001c3.626.002 7.02.12 7.539.264M37.57 100.02c3.084 1.88 1.605 6.804-2.043 6.8-3.74 0-5.127-4.88-1.94-6.826 1.055-.643 2.908-.63 3.983.026m56.48.206c1.512 1.108 2.015 3.413 1.079 4.95-2.46 4.034-8.612.827-6.557-3.419 1.01-2.085 3.695-2.837 5.478-1.53"></path>
          </svg>;
      case "elixir":
        return <svg viewBox="0 0 128 128">
            <linearGradient id="elixir-original-a" gradientUnits="userSpaceOnUse" x1="835.592" y1="-36.546" x2="821.211" y2="553.414" gradientTransform="matrix(.1297 0 0 .2 -46.03 17.198)">
              <stop offset="0" stopColor="#d9d8dc"></stop>
              <stop offset="1" stopColor="#fff" stopOpacity=".385"></stop>
            </linearGradient>
            <path fillRule="evenodd" clipRule="evenodd" fill="url(#elixir-original-a)" d="M64.4.5C36.7 13.9 1.9 83.4 30.9 113.9c26.8 33.5 85.4 1.3 68.4-40.5-21.5-36-35-37.9-34.9-72.9z"></path>
            <linearGradient id="elixir-original-b" gradientUnits="userSpaceOnUse" x1="942.357" y1="-40.593" x2="824.692" y2="472.243" gradientTransform="matrix(.1142 0 0 .2271 -47.053 17.229)">
              <stop offset="0" stopColor="#8d67af" stopOpacity=".672"></stop>
              <stop offset="1" stopColor="#9f8daf"></stop>
            </linearGradient>
            <path fillRule="evenodd" clipRule="evenodd" fill="url(#elixir-original-b)" d="M64.4.2C36.8 13.6 1.9 82.9 31 113.5c10.7 12.4 28 16.5 37.7 9.1 26.4-18.8 7.4-53.1 10.4-78.5C68.1 33.9 64.2 11.3 64.4.2z"></path>
            <linearGradient id="elixir-original-c" gradientUnits="userSpaceOnUse" x1="924.646" y1="120.513" x2="924.646" y2="505.851" gradientTransform="matrix(.1227 0 0 .2115 -46.493 17.206)">
              <stop offset="0" stopColor="#26053d" stopOpacity=".762"></stop>
              <stop offset="1" stopColor="#b7b4b4" stopOpacity=".278"></stop>
            </linearGradient>
            <path fillRule="evenodd" clipRule="evenodd" fill="url(#elixir-original-c)" d="M56.7 4.3c-22.3 15.9-28.2 75-24.1 94.2 8.2 48.1 75.2 28.3 69.6-16.5-6-29.2-48.8-39.2-45.5-77.7z"></path>
            <linearGradient id="elixir-original-d" gradientUnits="userSpaceOnUse" x1="428.034" y1="198.448" x2="607.325" y2="559.255" gradientTransform="matrix(.1848 0 0 .1404 -42.394 17.138)">
              <stop offset="0" stopColor="#91739f" stopOpacity=".46"></stop>
              <stop offset="1" stopColor="#32054f" stopOpacity=".54"></stop>
            </linearGradient>
            <path fillRule="evenodd" clipRule="evenodd" fill="url(#elixir-original-d)" d="M78.8 49.8c10.4 13.4 12.7 22.6 6.8 27.9-27.7 19.4-61.3 7.4-54-37.3C22.1 63 4.5 96.8 43.3 101.6c20.8 3.6 54 2 58.9-16.1-.2-15.9-10.8-22.9-23.4-35.7z"></path>
            <linearGradient id="elixir-original-e" gradientUnits="userSpaceOnUse" x1="907.895" y1="540.636" x2="590.242" y2="201.281" gradientTransform="matrix(.1418 0 0 .1829 -45.23 17.18)">
              <stop offset="0" stopColor="#463d49" stopOpacity=".331"></stop>
              <stop offset="1" stopColor="#340a50" stopOpacity=".821"></stop>
            </linearGradient>
            <path fillRule="evenodd" clipRule="evenodd" fill="url(#elixir-original-e)" d="M38.1 36.4c-2.9 21.2 35.1 77.9 58.3 71-17.7 35.6-56.9-21.2-64-41.7 1.5-11 2.2-16.4 5.7-29.3z"></path>
            <linearGradient id="elixir-original-f" gradientUnits="userSpaceOnUse" x1="1102.297" y1="100.542" x2="1008.071" y2="431.648" gradientTransform="matrix(.106 0 0 .2448 -47.595 17.242)">
              <stop offset="0" stopColor="#715383" stopOpacity=".145"></stop>
              <stop offset="1" stopColor="#f4f4f4" stopOpacity=".234"></stop>
            </linearGradient>
            <path fillRule="evenodd" clipRule="evenodd" fill="url(#elixir-original-f)" d="M60.4 49.7c.8 7.9 3.9 20.5 0 28.8S38.7 102 43.6 115.3c11.4 24.8 37.1-4.4 36.9-19 1.1-11.8-6.6-38.7-1.8-52.5L76.5 41l-13.6-4c-2.2 3.2-3 7.5-2.5 12.7z"></path>
            <linearGradient id="elixir-original-g" gradientUnits="userSpaceOnUse" x1="1354.664" y1="140.06" x2="1059.233" y2="84.466" gradientTransform="matrix(.09173 0 0 .2828 -48.536 17.28)">
              <stop offset="0" stopColor="#a5a1a8" stopOpacity=".356"></stop>
              <stop offset="1" stopColor="#370c50" stopOpacity=".582"></stop>
            </linearGradient>
            <path fillRule="evenodd" clipRule="evenodd" fill="url(#elixir-original-g)" d="M65.3 10.8C36 27.4 48 53.4 49.3 81.6l19.1-55.4c-1.4-5.7-2.3-9.5-3.1-15.4z"></path>
            <path fillRule="evenodd" clipRule="evenodd" fill="#330A4C" fillOpacity=".316" d="M68.3 26.1c-14.8 11.7-14.1 31.3-18.6 54 8.1-21.3 4.1-38.2 18.6-54z"></path>
            <path fillRule="evenodd" clipRule="evenodd" fill="#FFF" d="M45.8 119.7c8 1.1 12.1 2.2 12.5 3 .3 4.2-11.1 1.2-12.5-3z"></path>
            <path fillRule="evenodd" clipRule="evenodd" fill="#EDEDED" fillOpacity=".603" d="M49.8 10.8c-6.9 7.7-14.4 21.8-18.2 29.7-1 6.5-.5 15.7.6 23.5.9-18.2 7.5-39.2 17.6-53.2z"></path>
          </svg>;
      case "kotlin":
        return <svg viewBox="0 0 128 128">
            <defs>
              <linearGradient id="a" x1="500.003" x2="-.097" y1="579.106" y2="1079.206" gradientTransform="translate(15.534 -96.774) scale(.1939)" gradientUnits="userSpaceOnUse">
                <stop offset=".003" stopColor="#e44857"></stop>
                <stop offset=".469" stopColor="#c711e1"></stop>
                <stop offset="1" stopColor="#7f52ff"></stop>
              </linearGradient>
            </defs>
            <path fill="url(#a)" d="M112.484 112.484H15.516V15.516h96.968L64 64Zm0 0"></path>
          </svg>;
      case "swift":
        return <svg viewBox="0 0 128 128">
            <path fill="#f05138" d="M126.33 34.06a39.32 39.32 0 00-.79-7.83 28.78 28.78 0 00-2.65-7.58 28.84 28.84 0 00-4.76-6.32 23.42 23.42 0 00-6.62-4.55 27.27 27.27 0 00-7.68-2.53c-2.65-.51-5.56-.51-8.21-.76H30.25a45.46 45.46 0 00-6.09.51 21.82 21.82 0 00-5.82 1.52c-.53.25-1.32.51-1.85.76a33.82 33.82 0 00-5 3.28c-.53.51-1.06.76-1.59 1.26a22.41 22.41 0 00-4.76 6.32 23.61 23.61 0 00-2.65 7.58 78.5 78.5 0 00-.79 7.83v60.39a39.32 39.32 0 00.79 7.83 28.78 28.78 0 002.65 7.58 28.84 28.84 0 004.76 6.32 23.42 23.42 0 006.62 4.55 27.27 27.27 0 007.68 2.53c2.65.51 5.56.51 8.21.76h63.22a45.08 45.08 0 008.21-.76 27.27 27.27 0 007.68-2.53 30.13 30.13 0 006.62-4.55 22.41 22.41 0 004.76-6.32 23.61 23.61 0 002.65-7.58 78.49 78.49 0 00.79-7.83V34.06z"></path>
            <path fill="#fefefe" d="M85 96.5c-11.11 6.13-26.38 6.76-41.75.47A64.53 64.53 0 0113.84 73a50 50 0 0010.85 6.32c15.87 7.1 31.73 6.61 42.9 0-15.9-11.66-29.4-26.82-39.46-39.2a43.47 43.47 0 01-5.29-6.82c12.16 10.61 31.5 24 38.38 27.79a271.77 271.77 0 01-27-32.34 266.8 266.8 0 0044.47 34.87c.71.38 1.26.7 1.7 1a32.7 32.7 0 001.21-3.51c3.71-12.89-.53-27.54-9.79-39.67C93.25 33.81 106 57.05 100.66 76.51c-.14.53-.29 1-.45 1.55l.19.22c10.59 12.63 7.68 26 6.35 23.5C101 91 90.37 94.33 85 96.5z"></path>
          </svg>;
      case "edgeCloudflare":
        return <svg viewBox="0 0 128 128">
            <path fill="#FFF" d="m115.679 69.288-15.591-8.94-2.689-1.163-63.781.436v32.381h82.061z"></path>
            <path fill="#F38020" d="M87.295 89.022c.763-2.617.472-5.015-.8-6.796-1.163-1.635-3.125-2.58-5.488-2.689l-44.737-.581c-.291 0-.545-.145-.691-.363s-.182-.509-.109-.8c.145-.436.581-.763 1.054-.8l45.137-.581c5.342-.254 11.157-4.579 13.192-9.885l2.58-6.723c.109-.291.145-.581.073-.872-2.906-13.158-14.644-22.97-28.672-22.97-12.938 0-23.913 8.359-27.838 19.952a13.35 13.35 0 0 0-9.267-2.58c-6.215.618-11.193 5.597-11.811 11.811-.145 1.599-.036 3.162.327 4.615C10.104 70.051 2 78.337 2 88.549c0 .909.073 1.817.182 2.726a.895.895 0 0 0 .872.763h82.57c.472 0 .909-.327 1.054-.8l.617-2.216z"></path>
            <path fill="#FAAE40" d="M101.542 60.275c-.4 0-.836 0-1.236.036-.291 0-.545.218-.654.509l-1.744 6.069c-.763 2.617-.472 5.015.8 6.796 1.163 1.635 3.125 2.58 5.488 2.689l9.522.581c.291 0 .545.145.691.363.145.218.182.545.109.8-.145.436-.581.763-1.054.8l-9.924.582c-5.379.254-11.157 4.579-13.192 9.885l-.727 1.853c-.145.363.109.727.509.727h34.089c.4 0 .763-.254.872-.654.581-2.108.909-4.325.909-6.614 0-13.447-10.975-24.422-24.458-24.422"></path>
          </svg>;
      case "edgeFastly":
        return <svg viewBox="0 0 24 24">
            <path fill="#ff282d" d="M13.919 3.036V1.3h.632V0H9.377v1.3h.631v1.749a10.572 10.572 0 00-8.575 10.384C1.433 19.275 6.17 24 12 24c5.842 0 10.567-4.737 10.567-10.567 0-5.186-3.729-9.486-8.648-10.397zm-1.628 15.826v-.607h-.619v.607c-2.757-.158-4.955-2.38-5.101-5.137h.607v-.62h-.607a5.436 5.436 0 015.101-5.089v.607h.62v-.607a5.435 5.435 0 015.137 5.114h-.607v.619h.607a5.444 5.444 0 01-5.138 5.113zm2.26-7.712l-.39-.389-1.979 1.725a.912.912 0 00-.316-.06c-.534 0-.971.448-.971.995 0 .547.437.996.971.996.535 0 .972-.45.972-.996a.839.839 0 00-.049-.304Z" />
          </svg>;
      case "edgeLambda":
        return <svg viewBox="0 0 24 24">
            <path fill="#e57714" d="M4.9855 0c-.2941.0031-.5335.2466-.534.5482L4.446 5.456c0 .1451.06.2835.159.3891a.5322.5322 0 0 0 .3806.1562h3.4282l8.197 17.6805a.5365.5365 0 0 0 .4885.3181h5.811c.2969 0 .5426-.2448.5426-.5482V18.544c0-.3035-.2392-.5482-.5425-.5482h-2.0138L12.7394.3153C12.647.124 12.4564 0 12.2452 0h-7.254Zm.5397 1.0907h6.3678l8.16 17.6804a.5365.5365 0 0 0 .4885.3181h1.8178v3.8173H17.437L9.2402 5.226a.536.536 0 0 0-.4885-.318H5.5223Zm2.0137 8.2366c-.2098.0011-.3937.1193-.4857.3096L.6002 23.2133a.5506.5506 0 0 0 .0313.5282.5334.5334 0 0 0 .4544.25h6.169a.5468.5468 0 0 0 .497-.3096l3.38-7.166a.5405.5405 0 0 0-.0029-.4686L8.036 9.637a.5468.5468 0 0 0-.4942-.3096Zm.0057 1.8036 2.488 5.1522-3.1214 6.6206H1.9465Z" />
          </svg>;
      case "edgeUtils":
        return <svg viewBox="0 0 24 24" stroke="currentColor" fill="none" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <path d="M11 18.004h-4.343c-2.572 -.004 -4.657 -2.011 -4.657 -4.487c0 -2.475 2.085 -4.482 4.657 -4.482c.393 -1.762 1.794 -3.2 3.675 -3.773c1.88 -.572 3.956 -.193 5.444 1c1.488 1.19 2.162 3.007 1.77 4.769h.99a3.468 3.468 0 0 1 3.307 2.444"></path>
            <path d="M20 21l2 -2l-2 -2"></path>
            <path d="M17 17l-2 2l2 2"></path>
          </svg>;
      case "vercel":
        return <svg viewBox="0 0 128 128">
            <path d="M64.002 8.576 128 119.424H0Zm0 0"></path>
          </svg>;
      case "flutter":
        return <svg viewBox="0 0 128 128">
            <g fill="#3FB6D3">
              <path d="M12.3 64.2L76.3 0h39.4L32.1 83.6zM76.3 128h39.4L81.6 93.9l34.1-34.8H76.3L42.2 93.5z"></path>
            </g>
            <path fill="#27AACD" d="M81.6 93.9l-20-20-19.4 19.6 19.4 19.6z"></path>
            <path fill="#19599A" d="M115.7 128L81.6 93.9l-20 19.2L76.3 128z"></path>
            <linearGradient id="flutter-original-a" gradientUnits="userSpaceOnUse" x1="59.365" y1="116.36" x2="86.825" y2="99.399">
              <stop offset="0" stopColor="#1b4e94"></stop>
              <stop offset=".63" stopColor="#1a5497"></stop>
              <stop offset="1" stopColor="#195a9b"></stop>
            </linearGradient>
            <path fill="url(#flutter-original-a)" d="M61.6 113.1l30.8-8.4-10.8-10.8z"></path>
          </svg>;
      case "roku":
        return <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
            <path fill="var(--color-inverse)" d="M5.15 11.042a1.02 1.02 0 0 0-1.016-1.026H3.63v2.043h.504a1.02 1.02 0 0 0 1.016-1.017Zm2.292 4.072h-1.85l-1.468-2.038H3.63v2.033H2V9h2.335c1.346 0 2.445.915 2.445 2.042 0 .687-.421 1.3-1.062 1.676l1.724 2.396Z" />
            <path fill="var(--color-inverse)" d="M9.28 11.408c-.43 0-.797.585-.797 1.31 0 .725.366 1.31.797 1.31.44 0 .806-.586.806-1.31 0-.724-.366-1.31-.806-1.31Zm2.51 1.31a2.497 2.497 0 0 1-2.51 2.491 2.49 2.49 0 0 1-2.5-2.491 2.49 2.49 0 0 1 2.5-2.492 2.497 2.497 0 0 1 2.51 2.492Zm3.824-2.39-1.878 1.877v-1.884h-1.63v4.788h1.63v-1.943l1.96 1.943h2.052l-2.491-2.492 2.063-2.062v2.84c0 .944.567 1.814 1.996 1.814.678 0 1.3-.384 1.603-.732l.733.632H22v-4.781h-1.63v3.096c-.183.32-.439.521-.834.521-.401 0-.585-.237-.585-.998v-2.619h-3.337Z" />
          </svg>;
      default:
        return <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" viewBox="0 0 256 256">
            <path d="M69.12,94.15,28.5,128l40.62,33.85a8,8,0,1,1-10.24,12.29l-48-40a8,8,0,0,1,0-12.29l48-40a8,8,0,0,1,10.24,12.3Zm176,27.7-48-40a8,8,0,1,0-10.24,12.3L227.5,128l-40.62,33.85a8,8,0,1,0,10.24,12.29l48-40a8,8,0,0,0,0-12.29ZM162.73,32.48a8,8,0,0,0-10.25,4.79l-64,176a8,8,0,0,0,4.79,10.26A8.14,8.14,0,0,0,96,224a8,8,0,0,0,7.52-5.27l64-176A8,8,0,0,0,162.73,32.48Z"></path>
          </svg>;
    }
  };
  const GitBranch = () => {
    return <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" viewBox="0 0 256 256">
        <path d="M232,64a32,32,0,1,0-40,31v17a8,8,0,0,1-8,8H96a23.84,23.84,0,0,0-8,1.38V95a32,32,0,1,0-16,0v66a32,32,0,1,0,16,0V144a8,8,0,0,1,8-8h88a24,24,0,0,0,24-24V95A32.06,32.06,0,0,0,232,64ZM64,64A16,16,0,1,1,80,80,16,16,0,0,1,64,64ZM96,192a16,16,0,1,1-16-16A16,16,0,0,1,96,192ZM200,80a16,16,0,1,1,16-16A16,16,0,0,1,200,80Z"></path>
      </svg>;
  };
  const FileCode = () => {
    return <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" viewBox="0 0 256 256">
        <path d="M181.66,146.34a8,8,0,0,1,0,11.32l-24,24a8,8,0,0,1-11.32-11.32L164.69,152l-18.35-18.34a8,8,0,0,1,11.32-11.32Zm-72-24a8,8,0,0,0-11.32,0l-24,24a8,8,0,0,0,0,11.32l24,24a8,8,0,0,0,11.32-11.32L91.31,152l18.35-18.34A8,8,0,0,0,109.66,122.34ZM216,88V216a16,16,0,0,1-16,16H56a16,16,0,0,1-16-16V40A16,16,0,0,1,56,24h96a8,8,0,0,1,5.66,2.34l56,56A8,8,0,0,1,216,88Zm-56-8h28.69L160,51.31Zm40,136V96H152a8,8,0,0,1-8-8V40H56V216H200Z"></path>
      </svg>;
  };
  const Package = () => {
    return <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" viewBox="0 0 256 256">
        <path d="M223.68,66.15,135.68,18a15.88,15.88,0,0,0-15.36,0l-88,48.17a16,16,0,0,0-8.32,14v95.64a16,16,0,0,0,8.32,14l88,48.17a15.88,15.88,0,0,0,15.36,0l88-48.17a16,16,0,0,0,8.32-14V80.18A16,16,0,0,0,223.68,66.15ZM128,32l80.34,44-29.77,16.3-80.35-44ZM128,120,47.66,76l33.9-18.56,80.34,44ZM40,90l80,43.78v85.79L40,175.82Zm176,85.78h0l-80,43.79V133.82l32-17.51V152a8,8,0,0,0,16,0V107.55L216,90v85.77Z"></path>
      </svg>;
  };
  const sdkInfo = {
    js: {
      name: "JS SDK",
      version: "1.7.0",
      github: "https://github.com/growthbook/growthbook/tree/main/packages/sdk-js",
      examples: [{
        url: "https://github.com/growthbook/examples/tree/main/vanilla-typescript",
        name: "Typescript example app"
      }],
      packageRepos: [{
        name: "npm",
        url: "https://www.npmjs.com/package/@growthbook/growthbook"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        contextualBandits: "≥ v1.7.0"
      }, {
        caseInsensitiveMembership: "≥ v1.6.4"
      }, {
        caseInsensitiveRegex: "≥ v1.6.3"
      }, {
        trackingPlugin: "≥ v1.4.0"
      }, {
        savedGroupReferences: "≥ v1.1.0"
      }, {
        redirects: "≥ v0.36.0"
      }, {
        prerequisites: "≥ v0.34.0"
      }, {
        stickyBucketing: "≥ v0.32.0"
      }, {
        visualEditorDragDrop: "≥ v0.30.0"
      }, {
        remoteEval: "≥ v0.29.0"
      }, {
        semverTargeting: "≥ v0.27.0"
      }, {
        visualEditorJS: "≥ v0.27.0"
      }, {
        visualEditor: "≥ v0.24.0"
      }, {
        bucketingV2: "≥ v0.23.0"
      }, {
        streaming: "≥ v0.21.0"
      }, {
        encryption: "≥ v0.20.0"
      }, {
        looseUnmarshalling: "≥ v0.0.0"
      }, {
        namespacesV2: "≥ v0.0.0"
      }]
    },
    react: {
      name: "React SDK",
      version: "1.7.0",
      github: "https://github.com/growthbook/growthbook/tree/main/packages/sdk-react",
      examples: [{
        url: "https://github.com/growthbook/examples/tree/main/next-js",
        name: "Next.js example app"
      }, {
        url: "https://github.com/growthbook/examples/tree/main/next-js-pages",
        name: "Next.js pages example app"
      }, {
        url: "https://docs.growthbook.io/guide/create-react-app-and-growthbook",
        name: "Create React App guide"
      }],
      packageRepos: [{
        name: "npm",
        url: "https://www.npmjs.com/package/@growthbook/growthbook-react"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        contextualBandits: "≥ v1.7.0"
      }, {
        caseInsensitiveMembership: "≥ v1.6.4"
      }, {
        caseInsensitiveRegex: "≥ v1.6.3"
      }, {
        trackingPlugin: "≥ v1.4.0"
      }, {
        savedGroupReferences: "≥ v1.1.0"
      }, {
        redirects: "≥ v0.26.0"
      }, {
        prerequisites: "≥ v0.24.0"
      }, {
        stickyBucketing: "≥ v0.22.0"
      }, {
        visualEditorDragDrop: "≥ v0.20.0"
      }, {
        remoteEval: "≥ v0.19.0"
      }, {
        semverTargeting: "≥ v0.17.0"
      }, {
        visualEditorJS: "≥ v0.17.0"
      }, {
        visualEditor: "≥ v0.14.0"
      }, {
        bucketingV2: "≥ v0.13.0"
      }, {
        streaming: "≥ v0.11.0"
      }, {
        encryption: "≥ v0.10.1"
      }, {
        looseUnmarshalling: "≥ v0.0.0"
      }, {
        namespacesV2: "≥ v0.0.0"
      }]
    },
    nextjs: {
      name: "Next.js SDK",
      version: "0.1.0",
      github: "https://github.com/vercel/flags/tree/main/packages/adapter-growthbook",
      examples: [{
        url: "https://github.com/vercel/examples/tree/main/flags-sdk/growthbook",
        name: "Next.js Flags SDK example app"
      }],
      packageRepos: [{
        name: "npm",
        url: "https://www.npmjs.com/package/@flags-sdk/growthbook"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        savedGroupReferences: "≥ v0.1.0"
      }, {
        redirects: "≥ v0.1.0"
      }, {
        prerequisites: "≥ v0.1.0"
      }, {
        stickyBucketing: "≥ v0.1.0"
      }, {
        semverTargeting: "≥ v0.1.0"
      }, {
        bucketingV2: "≥ v0.1.0"
      }, {
        encryption: "≥ v0.1.0"
      }, {
        looseUnmarshalling: "≥ v0.1.0"
      }, {
        namespacesV2: "≥ v0.1.0"
      }]
    },
    php: {
      name: "PHP SDK",
      version: "2.6.1",
      github: "https://github.com/growthbook/growthbook-php",
      examples: [],
      packageRepos: [{
        name: "Packagist (Composer)",
        url: "https://packagist.org/packages/growthbook/growthbook"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        remoteEval: "≥ v2.5.0"
      }, {
        trackingPlugin: "≥ v2.4.0"
      }, {
        caseInsensitiveRegex: "≥ v2.3.0"
      }, {
        caseInsensitiveMembership: "≥ v2.3.0"
      }, {
        savedGroupReferences: "≥ v1.7.0"
      }, {
        prerequisites: "≥ v1.6.0"
      }, {
        stickyBucketing: "≥ v1.6.0"
      }, {
        semverTargeting: "≥ v1.5.0"
      }, {
        bucketingV2: "≥ v1.2.0"
      }, {
        encryption: "≥ v1.2.0"
      }, {
        looseUnmarshalling: "≥ v1.0.0"
      }, {
        namespacesV2: "≥ v1.0.0"
      }]
    },
    node: {
      name: "Node SDK",
      version: "1.7.0",
      github: "https://github.com/growthbook/growthbook/tree/main/packages/sdk-js",
      examples: [{
        url: "https://docs.growthbook.io/guide/express-js",
        name: "Express.js guide"
      }],
      packageRepos: [{
        name: "npm",
        url: "https://www.npmjs.com/package/@growthbook/growthbook"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        contextualBandits: "≥ v1.7.0"
      }, {
        caseInsensitiveMembership: "≥ v1.6.4"
      }, {
        caseInsensitiveRegex: "≥ v1.6.3"
      }, {
        trackingPlugin: "≥ v1.4.0"
      }, {
        savedGroupReferences: "≥ v1.1.0"
      }, {
        redirects: "≥ v0.36.0"
      }, {
        prerequisites: "≥ v0.34.0"
      }, {
        stickyBucketing: "≥ v0.32.0"
      }, {
        semverTargeting: "≥ v0.27.0"
      }, {
        bucketingV2: "≥ v0.23.0"
      }, {
        streaming: "≥ v0.21.0"
      }, {
        encryption: "≥ v0.20.0"
      }, {
        looseUnmarshalling: "≥ v0.0.0"
      }, {
        namespacesV2: "≥ v0.0.0"
      }]
    },
    ruby: {
      name: "Ruby SDK",
      version: "1.3.0",
      github: "https://github.com/growthbook/growthbook-ruby",
      examples: [{
        url: "https://github.com/growthbook/examples/tree/main/acme_donuts_rails",
        name: "Rails example app"
      }],
      packageRepos: [{
        name: "RubyGems",
        url: "https://rubygems.org/gems/growthbook"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        prerequisites: "≥ v1.3.0"
      }, {
        stickyBucketing: "≥ v1.3.0"
      }, {
        semverTargeting: "≥ v1.2.2"
      }, {
        encryption: "≥ v1.1.0"
      }, {
        bucketingV2: "≥ v1.0.0"
      }, {
        looseUnmarshalling: "≥ v0.0.0"
      }, {
        namespacesV2: "≥ v0.0.0"
      }]
    },
    python: {
      name: "Python SDK",
      version: "2.4.0",
      github: "https://github.com/growthbook/growthbook-python",
      examples: [],
      packageRepos: [{
        name: "PyPi",
        url: "https://pypi.org/project/growthbook/"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        remoteEval: "≥ v2.3.0"
      }, {
        trackingPlugin: "≥ v2.2.0"
      }, {
        caseInsensitiveMembership: "≥ v2.1.1"
      }, {
        caseInsensitiveRegex: "≥ v2.1.0"
      }, {
        savedGroupReferences: "≥ v1.2.1"
      }, {
        looseUnmarshalling: "≥ v1.1.0"
      }, {
        namespacesV2: "≥ v1.1.0"
      }, {
        prerequisites: "≥ v1.1.0"
      }, {
        stickyBucketing: "≥ v1.1.0"
      }, {
        semverTargeting: "≥ v1.1.0"
      }, {
        bucketingV2: "≥ v1.0.0"
      }, {
        encryption: "≥ v1.0.0"
      }]
    },
    go: {
      name: "Go SDK",
      version: "0.2.9",
      github: "https://github.com/growthbook/growthbook-golang",
      examples: [{
        url: "https://github.com/growthbook/examples/tree/main/go-example",
        name: "Go example app"
      }],
      packageRepos: [{
        name: "Go Modules",
        url: "https://pkg.go.dev/github.com/growthbook/growthbook-golang"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        trackingPlugin: "≥ v0.2.8"
      }, {
        caseInsensitiveMembership: "≥ v0.2.7"
      }, {
        caseInsensitiveRegex: "≥ v0.2.7"
      }, {
        stickyBucketing: "≥ v0.2.3"
      }, {
        prerequisites: "≥ v0.2.0"
      }, {
        savedGroupReferences: "≥ v0.2.0"
      }, {
        bucketingV2: "≥ v0.1.4"
      }, {
        streaming: "≥ v0.1.4"
      }, {
        semverTargeting: "≥ v0.1.4"
      }, {
        encryption: "≥ v0.1.4"
      }, {
        looseUnmarshalling: "≥ v0.0.0"
      }, {
        namespacesV2: "≥ v0.0.0"
      }]
    },
    rust: {
      name: "Rust SDK",
      version: "0.2.1",
      github: "https://github.com/growthbook/growthbook-rust",
      examples: [{
        url: "https://github.com/growthbook/growthbook-rust/tree/main/examples/client",
        name: "Rust example app"
      }],
      packageRepos: [{
        name: "crates.io",
        url: "https://crates.io/crates/growthbook-rust"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        savedGroupReferences: "≥ v0.2.0"
      }, {
        caseInsensitiveRegex: "≥ v0.1.1"
      }, {
        caseInsensitiveMembership: "≥ v0.1.1"
      }, {
        stickyBucketing: "≥ v0.1.0"
      }, {
        encryption: "≥ v0.0.1"
      }, {
        looseUnmarshalling: "≥ v0.0.1"
      }, {
        namespacesV2: "≥ v0.0.1"
      }, {
        prerequisites: "≥ v0.0.1"
      }, {
        semverTargeting: "≥ v0.0.1"
      }, {
        bucketingV2: "≥ v0.0.1"
      }]
    },
    java: {
      name: "Java SDK",
      version: "0.10.10",
      github: "https://github.com/growthbook/growthbook-sdk-java",
      examples: [{
        url: "https://github.com/growthbook/examples/tree/main/jvm-spring-web",
        name: "JVM with Spring Web example app"
      }, {
        url: "https://github.com/growthbook/examples/tree/main/jvm-kotlin-ktor-example",
        name: "JVM with Kotlin Ktor example app"
      }, {
        url: "https://github.com/growthbook/examples/tree/main/android-example",
        name: "Android example app"
      }, {
        url: "https://growthbook.github.io/growthbook-sdk-java/",
        name: "JavaDoc class docs"
      }],
      packageRepos: [{
        name: "JitPack",
        url: "https://jitpack.io/#growthbook/growthbook-sdk-java"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        caseInsensitiveMembership: "≥ v0.10.9"
      }, {
        caseInsensitiveRegex: "≥ v0.10.6"
      }, {
        remoteEval: "≥ v0.9.92"
      }, {
        prerequisites: "≥ v0.9.3"
      }, {
        stickyBucketing: "≥ v0.9.3"
      }, {
        streaming: "≥ v0.9.0"
      }, {
        semverTargeting: "≥ v0.7.0"
      }, {
        bucketingV2: "≥ v0.6.0"
      }, {
        encryption: "≥ v0.3.0"
      }, {
        looseUnmarshalling: "≥ v0.0.0"
      }, {
        namespacesV2: "≥ v0.0.0"
      }]
    },
    csharp: {
      name: "C# SDK",
      version: "1.2.0",
      github: "https://github.com/growthbook/growthbook-c-sharp",
      examples: [{
        url: "https://github.com/growthbook/examples/tree/main/csharp-example/GrowthBookCSharpExamples",
        name: "C# example app"
      }],
      packageRepos: [{
        name: "NuGet",
        url: "https://www.nuget.org/packages/growthbook-c-sharp"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        caseInsensitiveMembership: "≥ v1.2.0"
      }, {
        caseInsensitiveRegex: "≥ v1.2.0"
      }, {
        remoteEval: "≥ v1.1.3"
      }, {
        stickyBucketing: "≥ v1.1.0"
      }, {
        prerequisites: "≥ v1.1.0"
      }, {
        savedGroupReferences: "≥ v1.1.0"
      }, {
        encryption: "≥ v1.0.0"
      }, {
        streaming: "≥ v1.0.0"
      }, {
        bucketingV2: "≥ v1.0.0"
      }, {
        semverTargeting: "≥ v1.0.0"
      }, {
        looseUnmarshalling: "≥ v0.0.0"
      }, {
        namespacesV2: "≥ v0.0.0"
      }]
    },
    elixir: {
      name: "Elixir SDK",
      version: "0.3.0",
      github: "https://github.com/growthbook/growthbook-elixir",
      examples: [],
      packageRepos: [{
        name: "Hex",
        url: "https://www.hex.pm/packages/growthbook"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        encryption: "≥ v0.3.0"
      }, {
        prerequisites: "≥ v0.2.0"
      }, {
        semverTargeting: "≥ v0.2.0"
      }, {
        bucketingV2: "≥ v0.2.0"
      }, {
        looseUnmarshalling: "≥ v0.2.0"
      }, {
        namespacesV2: "≥ v0.2.0"
      }]
    },
    kotlin: {
      name: "Kotlin SDK",
      version: "7.6.0",
      github: "https://github.com/growthbook/growthbook-kotlin",
      examples: [],
      packageRepos: [{
        name: "Maven Central",
        url: "https://mvnrepository.com/artifact/io.growthbook.sdk/GrowthBook"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        caseInsensitiveMembership: "≥ v7.1.1"
      }, {
        caseInsensitiveRegex: "≥ v7.1.1"
      }, {
        remoteEval: "≥ v1.1.50"
      }, {
        streaming: "≥ v1.1.50"
      }, {
        prerequisites: "≥ v1.1.44"
      }, {
        stickyBucketing: "≥ v1.1.44"
      }, {
        bucketingV2: "≥ v1.1.38"
      }, {
        semverTargeting: "≥ v1.1.31"
      }, {
        encryption: "≥ v1.1.23"
      }, {
        looseUnmarshalling: "≥ v0.0.0"
      }, {
        namespacesV2: "≥ v0.0.0"
      }]
    },
    swift: {
      name: "Swift SDK",
      version: "1.2.0",
      github: "https://github.com/growthbook/growthbook-swift",
      examples: [],
      packageRepos: [{
        name: "Swift Package Manager (SPM)",
        url: "https://swiftpackageindex.com/growthbook/growthbook-swift"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        namespacesV2: "≥ v1.1.4"
      }, {
        caseInsensitiveMembership: "≥ v1.1.1"
      }, {
        caseInsensitiveRegex: "≥ v1.1.1"
      }, {
        remoteEval: "≥ v1.0.50"
      }, {
        stickyBucketing: "≥ v1.0.49"
      }, {
        prerequisites: "≥ v1.0.49"
      }, {
        bucketingV2: "≥ v1.0.43"
      }, {
        streaming: "≥ v1.0.43"
      }, {
        semverTargeting: "≥ v1.0.38"
      }, {
        encryption: "≥ v1.0.35"
      }, {
        looseUnmarshalling: "≥ v0.0.0"
      }]
    },
    reactNative: {
      name: "React Native SDK",
      version: "1.7.0",
      github: "https://github.com/growthbook/growthbook/tree/main/packages/sdk-react",
      examples: [{
        url: "https://github.com/growthbook/examples/tree/main/react-native-cli",
        name: "React Native CLI example app"
      }],
      packageRepos: [{
        name: "npm",
        url: "https://www.npmjs.com/package/@growthbook/growthbook-react"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        contextualBandits: "≥ v1.7.0"
      }, {
        caseInsensitiveMembership: "≥ v1.6.4"
      }, {
        caseInsensitiveRegex: "≥ v1.6.3"
      }, {
        trackingPlugin: "≥ v1.4.0"
      }, {
        savedGroupReferences: "≥ v1.1.0"
      }, {
        redirects: "≥ v0.26.0"
      }, {
        prerequisites: "≥ v0.24.0"
      }, {
        stickyBucketing: "≥ v0.22.0"
      }, {
        visualEditorDragDrop: "≥ v0.20.0"
      }, {
        remoteEval: "≥ v0.19.0"
      }, {
        semverTargeting: "≥ v0.17.0"
      }, {
        visualEditorJS: "≥ v0.17.0"
      }, {
        visualEditor: "≥ v0.14.0"
      }, {
        bucketingV2: "≥ v0.13.0"
      }, {
        streaming: "≥ v0.11.0"
      }, {
        encryption: "≥ v0.10.1"
      }, {
        looseUnmarshalling: "≥ v0.0.0"
      }, {
        namespacesV2: "≥ v0.0.0"
      }]
    },
    edgeCloudflare: {
      name: "Cloudflare Workers App & SDK",
      version: "0.2.9",
      github: "https://github.com/growthbook/growthbook-proxy/tree/main/packages/lib/edge-cloudflare",
      examples: [{
        url: "https://github.com/growthbook/growthbook-proxy/tree/main/packages/lib/edge-cloudflare/example",
        name: "Example worker"
      }],
      packageRepos: [{
        name: "npm",
        url: "https://www.npmjs.com/package/@growthbook/edge-cloudflare"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        caseInsensitiveRegex: "≥ v0.2.7"
      }, {
        caseInsensitiveMembership: "≥ v0.2.7"
      }, {
        savedGroupReferences: "≥ v0.1.12"
      }, {
        looseUnmarshalling: "≥ v0.1.11"
      }, {
        namespacesV2: "≥ v0.1.11"
      }, {
        encryption: "≥ v0.1.11"
      }, {
        streaming: "≥ v0.1.11"
      }, {
        bucketingV2: "≥ v0.1.11"
      }, {
        visualEditor: "≥ v0.1.11"
      }, {
        semverTargeting: "≥ v0.1.11"
      }, {
        visualEditorJS: "≥ v0.1.11"
      }, {
        visualEditorDragDrop: "≥ v0.1.11"
      }, {
        prerequisites: "≥ v0.1.11"
      }, {
        redirects: "≥ v0.1.11"
      }, {
        stickyBucketing: "≥ v0.1.11"
      }]
    },
    edgeFastly: {
      name: "Fastly Compute App & SDK",
      version: "0.2.9",
      github: "https://github.com/growthbook/growthbook-proxy/tree/main/packages/lib/edge-fastly",
      examples: [{
        url: "https://github.com/growthbook/growthbook-proxy/tree/main/packages/lib/edge-fastly/example",
        name: "Example compute worker"
      }],
      packageRepos: [{
        name: "npm",
        url: "https://www.npmjs.com/package/@growthbook/edge-fastly"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        caseInsensitiveRegex: "≥ v0.2.7"
      }, {
        caseInsensitiveMembership: "≥ v0.2.7"
      }, {
        savedGroupReferences: "≥ v0.1.6"
      }, {
        looseUnmarshalling: "≥ v0.1.5"
      }, {
        namespacesV2: "≥ v0.1.5"
      }, {
        encryption: "≥ v0.1.5"
      }, {
        streaming: "≥ v0.1.5"
      }, {
        bucketingV2: "≥ v0.1.5"
      }, {
        visualEditor: "≥ v0.1.5"
      }, {
        semverTargeting: "≥ v0.1.5"
      }, {
        visualEditorJS: "≥ v0.1.5"
      }, {
        visualEditorDragDrop: "≥ v0.1.5"
      }, {
        prerequisites: "≥ v0.1.5"
      }, {
        redirects: "≥ v0.1.5"
      }, {
        stickyBucketing: "≥ v0.1.5"
      }]
    },
    edgeLambda: {
      name: "Lambda@Edge App & SDK",
      version: "0.0.29",
      github: "https://github.com/growthbook/growthbook-proxy/tree/main/packages/lib/edge-lambda",
      examples: [],
      packageRepos: [{
        name: "npm",
        url: "https://www.npmjs.com/package/@growthbook/edge-lambda"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        caseInsensitiveRegex: "≥ v0.0.27"
      }, {
        caseInsensitiveMembership: "≥ v0.0.27"
      }, {
        savedGroupReferences: "≥ v0.0.7"
      }, {
        looseUnmarshalling: "≥ v0.0.6"
      }, {
        namespacesV2: "≥ v0.0.6"
      }, {
        encryption: "≥ v0.0.6"
      }, {
        streaming: "≥ v0.0.6"
      }, {
        bucketingV2: "≥ v0.0.6"
      }, {
        visualEditor: "≥ v0.0.6"
      }, {
        semverTargeting: "≥ v0.0.6"
      }, {
        visualEditorJS: "≥ v0.0.6"
      }, {
        visualEditorDragDrop: "≥ v0.0.6"
      }, {
        prerequisites: "≥ v0.0.6"
      }, {
        redirects: "≥ v0.0.6"
      }, {
        stickyBucketing: "≥ v0.0.6"
      }]
    },
    edgeUtils: {
      name: "Edge Utils",
      version: "0.2.9",
      github: "https://github.com/growthbook/growthbook-proxy/tree/main/packages/lib/edge-utils",
      examples: [],
      packageRepos: [{
        name: "npm",
        url: "https://www.npmjs.com/package/@growthbook/edge-utils"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        caseInsensitiveRegex: "≥ v0.2.7"
      }, {
        caseInsensitiveMembership: "≥ v0.2.7"
      }, {
        savedGroupReferences: "≥ v0.1.5"
      }, {
        looseUnmarshalling: "≥ v0.1.4"
      }, {
        namespacesV2: "≥ v0.1.4"
      }, {
        encryption: "≥ v0.1.4"
      }, {
        streaming: "≥ v0.1.4"
      }, {
        bucketingV2: "≥ v0.1.4"
      }, {
        visualEditor: "≥ v0.1.4"
      }, {
        semverTargeting: "≥ v0.1.4"
      }, {
        visualEditorJS: "≥ v0.1.4"
      }, {
        visualEditorDragDrop: "≥ v0.1.4"
      }, {
        prerequisites: "≥ v0.1.4"
      }, {
        redirects: "≥ v0.1.4"
      }, {
        stickyBucketing: "≥ v0.1.4"
      }]
    },
    flutter: {
      name: "Flutter SDK",
      version: "4.4.0",
      github: "https://github.com/growthbook/growthbook-flutter",
      examples: [],
      packageRepos: [{
        name: "pub.dev",
        url: "https://pub.dev/packages/growthbook_sdk_flutter"
      }],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        trackingPlugin: "≥ v4.4.0"
      }, {
        caseInsensitiveRegex: "≥ v4.3.0"
      }, {
        caseInsensitiveMembership: "≥ v4.3.0"
      }, {
        savedGroupReferences: "≥ v3.9.4"
      }, {
        stickyBucketing: "≥ v3.8.0"
      }, {
        remoteEval: "≥ v3.7.0"
      }, {
        streaming: "≥ v3.4.0"
      }, {
        prerequisites: "≥ v3.2.0"
      }, {
        encryption: "≥ v3.1.0"
      }, {
        bucketingV2: "≥ v3.1.0"
      }, {
        semverTargeting: "≥ v3.1.0"
      }, {
        looseUnmarshalling: "≥ v0.0.0"
      }, {
        namespacesV2: "≥ v0.0.0"
      }]
    },
    roku: {
      name: "Roku SDK",
      version: "1.4.1",
      github: "https://github.com/growthbook/growthbook-roku",
      examples: [{
        url: "https://github.com/growthbook/growthbook-roku/tree/main/examples",
        name: "Roku examples"
      }, {
        url: "https://www.npmjs.com/package/growthbook-roku",
        name: "npm package"
      }],
      packageRepos: [],
      capabilities: [{
        features: "All versions"
      }, {
        experimentation: "All versions"
      }, {
        encryption: "≥ v1.4.1"
      }, {
        stickyBucketing: "≥ v1.4.1"
      }, {
        prerequisites: "≥ v1.3.0"
      }, {
        looseUnmarshalling: "≥ v1.3.0"
      }, {
        namespacesV2: "≥ v1.3.0"
      }, {
        semverTargeting: "≥ v1.3.0"
      }, {
        bucketingV2: "≥ v1.3.0"
      }]
    }
  };
  const SLACK_URL = "https://join.slack.com/t/growthbookusers/shared_invite/zt-2xw8fu279-Y~hwnfCEf7WrEI9qScHURQ";
  const Row = ({href, icon, children}) => {
    const rowClass = "mint-flex mint-items-center mint-gap-2 mint-p-3 mint-border-b mint-border-[#00002f26] dark:mint-border-[#d6ebfd30]";
    const iconSpan = <span className="inline-flex items-center justify-center w-[1.2em] h-[1.2em] shrink-0 [&_svg]:w-full [&_svg]:h-full">
        {icon}
      </span>;
    if (href) {
      return <a href={href} target="_blank" rel="noreferrer" className={rowClass + " mint-text-inherit mint-no-underline hover:mint-text-inherit hover:mint-underline"}>
          {iconSpan}
          {children}
        </a>;
    }
    return <div className={rowClass}>
        {iconSpan}
        {children}
      </div>;
  };
  const {name, version, github, examples, packageRepos} = sdkInfo[sdk];
  const formattedVersion = version.replace(/^v?/, "v");
  const githubName = github.split("/").pop();
  return <section className="grid mb-4">
      <header className="col-span-full flex justify-between items-center gap-4 p-3 border-b border-[#00002f26] dark:border-[#d6ebfd30]">
        <div className="font-semibold flex items-center gap-2 dark:text-[#f5f7f5]">
          <span className="inline-flex items-center justify-center w-[1.2em] h-[1.2em] shrink-0 [&_svg]:w-full [&_svg]:h-full">
            <CodeLogos name={sdk} />
          </span>
          <span>{name} Resources</span>
        </div>
        <div className="flex items-center gap-2">
          <span className="inline-flex items-center justify-center w-[1.2em] h-[1.2em] shrink-0 [&_svg]:w-full [&_svg]:h-full">
            <GitBranch />
          </span>
          {formattedVersion}
        </div>
      </header>

      <Row href={github} icon={<GitHubLogo />}>
        {githubName}
      </Row>

      {packageRepos.map(repo => <Row key={repo.name} href={repo.url} icon={<Package />}>
          {repo.name}
        </Row>)}

      {examples.map(({url, name}) => <Row key={name} href={url} icon={<FileCode />}>
          {name}
        </Row>)}

      <Row href={SLACK_URL} icon={<SlackLogo />}>
        Get help on Slack
      </Row>
    </section>;
};

*Requires **Python 3.6** or above*

<SdkResources sdk="python" />

## Installation

```bash theme={null}
pip install growthbook
```

## Quick Usage

```python theme={null}
from growthbook import GrowthBook

# User attributes for targeting and experimentation
attributes = {
  "id": "123",
  "customUserAttribute": "foo"
}

def on_experiment_viewed(experiment, result):
  # Use whatever event tracking system you want
  analytics.track(attributes["id"], "Experiment Viewed", {
    'experimentId': experiment.key,
    'variationId': result.key
  })

# Create a GrowthBook instance
gb = GrowthBook(
  attributes = attributes,
  on_experiment_viewed = on_experiment_viewed,
  api_host = "https://cdn.growthbook.io",
  client_key = "sdk-abc123"
)

# Load features from the GrowthBook API with caching
gb.load_features()

# Simple on/off feature gating
if gb.is_on("my-feature"):
  print("My feature is on!")

# Get the value of a feature with a fallback
color = gb.get_feature_value("button-color-feature", "blue")
```

## Async Client (Recommended)

**Available starting in version 1.2.0**

For improved performance and better resource utilization, especially in async web applications, use the `GrowthBookClient` class. This approach provides up to **3x better performance** by reusing a single client instance across multiple requests instead of creating new instances per request.

### Basic Async Usage

```python theme={null}
from growthbook import GrowthBookClient, Options, UserContext, FeatureRefreshStrategy
import asyncio

async def main():
    # Create client options
    options = Options(
        api_host="https://cdn.growthbook.io",
        client_key="sdk-abc123",
        # Optional: Enable real-time feature updates
        refresh_strategy=FeatureRefreshStrategy.SERVER_SENT_EVENTS
    )

    # Create and initialize client
    client = GrowthBookClient(options)
    try:
        # Initialize the client before using it
        success = await client.initialize()
        if not success:
            print("Failed to initialize GrowthBook client")
            return

        # Create user context for targeting
        user = UserContext(
            attributes={
                "id": "123",
                "country": "US",
                "premium": True
            }
        )

        # Simple feature evaluation
        if await client.is_on("new-homepage", user):
            print("New homepage is enabled!")

        # Get feature value with fallback
        color = await client.get_feature_value("button-color", "blue", user)
        print(f"Button color is {color}")

        # Run an experiment
        from growthbook import Experiment
        result = await client.run(
            Experiment(
                key="my-test",
                variations=["A", "B"]
            ),
            user
        )
        print(f"User got variation: {result.value}")
    finally:
        # Always close the client when done
        await client.close()

# Run the async code
asyncio.run(main())
```

For web framework integration examples, see [Integration Examples](#integration-examples) below.

### Real-time Feature Updates

The async client supports real-time feature updates using Server-Sent Events:

```python theme={null}
from growthbook import GrowthBookClient, Options, FeatureRefreshStrategy

client = GrowthBookClient(
    Options(
        api_host="https://cdn.growthbook.io",
        client_key="sdk-abc123",
        # Enable SSE for real-time updates
        refresh_strategy=FeatureRefreshStrategy.SERVER_SENT_EVENTS
    )
)
```

### Concurrency and Thread Safety

The async client is designed to be thread-safe and handle concurrent requests efficiently. You can safely use a single client instance across multiple coroutines:

```python theme={null}
from fastapi import FastAPI
from growthbook import GrowthBookClient, Options, UserContext
import asyncio

app = FastAPI()

# Single client instance shared across all requests
gb_client = GrowthBookClient(Options(
    api_host="https://cdn.growthbook.io",
    client_key="sdk-abc123"
))

@app.on_event("startup")
async def startup():
    await gb_client.initialize()

@app.on_event("shutdown")
async def shutdown():
    await gb_client.close()

@app.get("/batch")
async def batch_process(user_ids: list[str]):
    # Safely process multiple users concurrently
    tasks = []
    for user_id in user_ids:
        user = UserContext(attributes={"id": user_id})
        tasks.append(gb_client.eval_feature("new-feature", user))

    results = await asyncio.gather(*tasks)
    return {"results": results}
```

**Note**: While the client is thread-safe, you should not share a single `UserContext` instance across different requests. Create a new `UserContext` for each request to maintain proper isolation.

### Performance Benefits

The `GrowthBookClient` provides significant performance improvements over the traditional per-request `GrowthBook` approach:

* **3x faster** feature evaluations due to instance reuse
* **Lower memory usage** by sharing feature data across requests
* **Built-in caching** with configurable refresh strategies
* **Real-time updates** without polling overhead
* **Async/await support** for non-blocking operations

## Loading Features

There are two ways to load feature flags into the GrowthBook SDK. You can either use the built-in fetching/caching logic or implement your own custom solution.

### Built-in Fetching and Caching

Both the async client and traditional client support built-in fetching and caching of feature flags.

<Tabs>
  <Tab title="Async Client">
    For the async client, use `GrowthBookClient` with `Options`:

    ```python theme={null}
    import asyncio
    from growthbook import GrowthBookClient, Options, FeatureRefreshStrategy

    async def main():
        # Create client with built-in fetching and caching
        client = GrowthBookClient(
            Options(
                api_host="https://cdn.growthbook.io",
                client_key="sdk-abc123",
                # Optional: Configure caching
                cache_ttl=300,  # Cache for 5 minutes
                # Optional: Enable real-time updates
                refresh_strategy=FeatureRefreshStrategy.SERVER_SENT_EVENTS,
                # Optional: Encryption support
                decryption_key="your-decryption-key"
            )
        )

        try:
            # Initialize features (async)
            await client.initialize()

            # Features are now cached and ready to use
            user = UserContext(attributes={"id": "user_123"})
            feature_enabled = await client.is_on("my-feature", user)

            print(f"Feature enabled: {feature_enabled}")

        finally:
            await client.close()

    asyncio.run(main())
    ```
  </Tab>

  <Tab title="Legacy Client">
    For the traditional client, pass `api_host` and `client_key` to the constructor:

    ```python theme={null}
    from growthbook import GrowthBook

    # Create client with built-in fetching and caching
    gb = GrowthBook(
        api_host="https://cdn.growthbook.io",
        client_key="sdk-abc123",
      # How long to cache features in seconds (Optional, default 60s)
        cache_ttl=60,
        # Optional: Encryption support
        decryption_key="your-decryption-key",
        # User attributes
        attributes={"id": "user_123"}
    )

    # Load features (synchronous)
    gb.load_features()

    # Features are now cached and ready to use
    feature_enabled = gb.is_on("my-feature")
    print(f"Feature enabled: {feature_enabled}")

    # Clean up
    gb.destroy()
    ```
  </Tab>
</Tabs>

#### Custom Caching

GrowthBook comes with a custom in-memory cache.

<Tabs>
  <Tab title="Legacy Client">
    For the traditional client, configure a custom cache globally:

    ```python theme={null}
    from redis import Redis
    import json
    from growthbook import GrowthBook, AbstractFeatureCache, feature_repo

    class RedisFeatureCache(AbstractFeatureCache):
      def __init__(self):
        self.r = Redis(host='localhost', port=6379)
        self.prefix = "gb:"

      def get(self, key: str):
        data = self.r.get(self.prefix + key)
        # Data stored as a JSON string, parse into dict before returning
        return None if data is None else json.loads(data)

      def set(self, key: str, value: dict, ttl: int) -> None:
        self.r.set(self.prefix + key, json.dumps(value))
        self.r.expire(self.prefix + key, ttl)

    # Configure GrowthBook to use your custom cache class
    feature_repo.set_cache(RedisFeatureCache())

    # Now all GrowthBook instances will use Redis caching
    gb = GrowthBook(
        api_host="https://cdn.growthbook.io",
        client_key="sdk-abc123"
    )
    gb.load_features()  # Will use Redis cache
    ```
  </Tab>
</Tabs>

### Custom Implementation

If you prefer to handle the entire fetching/caching logic yourself, you can just pass in a `dict` of features from the GrowthBook API directly into the constructor:

```python theme={null}
# From the GrowthBook API
features = {'my-feature':{'defaultValue':False}}

gb = GrowthBook(
  features = features
)
```

Note: When doing this, you do not need to specify your `api_host` or `client_key` and you don't need to call `gb.load_features()`.

## GrowthBook class

The GrowthBook constructor has the following parameters:

* **enabled** (`bool`) - Flag to globally disable all experiments. Default true.
* **attributes** (`dict`) - Dictionary of user attributes that are used for targeting and to assign variations
* **url** (`str`) - The URL of the current request (if applicable)
* **qa\_mode** (`boolean`) - If true, random assignment is disabled and only explicitly forced variations are used.
* **on\_experiment\_viewed** (`callable`) - A function that takes `experiment` and `result` as arguments.
* **api\_host** (`str`) - The GrowthBook API host to fetch feature flags from. Defaults to `https://cdn.growthbook.io`
* **client\_key** (`str`) - The client key that will be passed to the API Host to fetch feature flags
* **decryption\_key** (`str`) - If the GrowthBook API endpoint has encryption enabled, specify the decryption key here
* **cache\_ttl** (`int`) - How long to cache features in-memory from the GrowthBook API (seconds, default `60`)
* **features** (`dict`) - Feature definitions from the GrowthBook API (only required if `client_key` is not specified)
* **forced\_variations** (`dict`) - Dictionary of forced experiment variations (used for QA)

There are also getter and setter methods for features and attributes if you need to update them later in the request:

```python theme={null}
gb.set_features(gb.get_features())
gb.set_attributes(gb.get_attributes())
```

### Attributes

You can specify attributes about the current user and request. These are used for two things:

1. Feature targeting (e.g. paid users get one value, free users get another)
2. Assigning persistent variations in A/B tests (e.g. user id "123" always gets variation B)

Attributes can be any JSON data type - boolean, integer, float, string, list, or dict.

<Tabs>
  <Tab title="Async Client">
    For the async client, attributes are passed via `UserContext` for each evaluation:

    ```python theme={null}
    import asyncio
    from growthbook import GrowthBookClient, Options, UserContext

    async def main():
        client = GrowthBookClient(
            Options(
                api_host="https://cdn.growthbook.io",
                client_key="sdk-abc123"
            )
        )

        try:
            await client.initialize()

            # Create user context with attributes
            user = UserContext(
                attributes={
      'id': "123",
      'loggedIn': True,
      'age': 21.5,
      'tags': ["tag1", "tag2"],
      'account': {
        'age': 90
                    },
                    'country': 'US',
                    'premium': True
                }
            )

            # Use features with user context
            feature_enabled = await client.is_on("premium-feature", user)
            discount = await client.get_feature_value("discount-percent", 0, user)

            # Different user context for another request
            guest_user = UserContext(
                attributes={
                    'id': "guest_456",
                    'loggedIn': False,
                    'country': 'CA'
                }
            )

            guest_feature = await client.is_on("premium-feature", guest_user)

        finally:
            await client.close()

    asyncio.run(main())
    ```
  </Tab>

  <Tab title="Legacy Client">
    For the traditional client, attributes are set globally on the instance:

    ```python theme={null}
    from growthbook import GrowthBook

    # Define user attributes
    attributes = {
        'id': "123",
        'loggedIn': True,
        'age': 21.5,
        'tags': ["tag1", "tag2"],
        'account': {
            'age': 90
        },
        'country': 'US',
        'premium': True
    }

    # Pass into constructor
    gb = GrowthBook(
        api_host="https://cdn.growthbook.io",
        client_key="sdk-abc123",
        attributes=attributes
    )

    gb.load_features()

    # Use features (uses global attributes)
    feature_enabled = gb.is_on("premium-feature")
    discount = gb.get_feature_value("discount-percent", 0)

    # Or update attributes later
    new_attributes = {
        'id': "456",
        'loggedIn': False,
        'country': 'CA'
    }
    gb.set_attributes(new_attributes)

    # Features will now use updated attributes
    updated_feature = gb.is_on("premium-feature")

    gb.destroy()
    ```
  </Tab>
</Tabs>

#### Secure Attributes

When *secure attribute hashing* is enabled, all targeting conditions in the SDK payload referencing attributes with datatype `secureString` or `secureString[]` will be anonymized via SHA-256 hashing. This allows you to safely target users based on sensitive attributes. You must enable this feature in your SDK Connection for it to take effect.

If your SDK Connection has secure attribute hashing enabled, you will need to manually hash any `secureString` or `secureString[]` attributes that you pass into the GrowthBook SDK.

To hash an attribute, use the `hashlib` library with SHA-256 support, and compute the SHA-256 hashed value of your attribute *plus* your organization's secure attribute salt.

<Tabs>
  <Tab title="Async Client">
    For the async client, hash secure attributes before creating the `UserContext`:

    ```python theme={null}
    import asyncio
    import hashlib
    from growthbook import GrowthBookClient, Options, UserContext

    def hash_secure_attribute(value: str, salt: str) -> str:
        """Helper function to hash secure attributes"""
        return hashlib.sha256(f"{salt}{value}".encode()).hexdigest()

    async def main():
    # Your secure attribute salt (set in Organization Settings)
    salt = "f09jq3fij"

        client = GrowthBookClient(
            Options(
                api_host="https://cdn.growthbook.io",
                client_key="sdk-abc123"
            )
        )

        try:
            await client.initialize()

            # Hash secure attributes
            user_email = "user@example.com"
            user_tags = ["premium", "beta"]

            hashed_email = hash_secure_attribute(user_email, salt)
            hashed_tags = [hash_secure_attribute(tag, salt) for tag in user_tags]

            # Create user context with hashed secure attributes
            user = UserContext(
                attributes={
                    'id': "123",
                    'loggedIn': True,
                    'email': hashed_email,  # secureString
                    'tags': hashed_tags,    # secureString[]
                    'country': 'US'         # regular attribute
                }
            )

            # Use features with secure attributes
            premium_feature = await client.is_on("premium-feature", user)
            personalized_content = await client.get_feature_value("personalized-content", {}, user)

        finally:
            await client.close()

    asyncio.run(main())
    ```
  </Tab>

  <Tab title="Legacy Client">
    For the traditional client, hash secure attributes before passing to the constructor:

    ```python theme={null}
    import hashlib
    from growthbook import GrowthBook

    def hash_secure_attribute(value: str, salt: str) -> str:
        """Helper function to hash secure attributes"""
        return hashlib.sha256(f"{salt}{value}".encode()).hexdigest()

    # Your secure attribute salt (set in Organization Settings)
    salt = "f09jq3fij"

    # Hash secure attributes
    user_email = "user@example.com"
    user_tags = ["premium", "beta"]

    hashed_email = hash_secure_attribute(user_email, salt)
    hashed_tags = [hash_secure_attribute(tag, salt) for tag in user_tags]

    # Create GrowthBook instance with hashed secure attributes
    gb = GrowthBook(
        api_host="https://cdn.growthbook.io",
        client_key="sdk-abc123",
        attributes={
        'id': "123",
        'loggedIn': True,
            'email': hashed_email,  # secureString
            'tags': hashed_tags,    # secureString[]
            'country': 'US'         # regular attribute
        }
    )

    gb.load_features()

    # Use features with secure attributes
    premium_feature = gb.is_on("premium-feature")
    personalized_content = gb.get_feature_value("personalized-content", {})

    gb.destroy()
    ```
  </Tab>
</Tabs>

### Tracking Experiments

Any time an experiment is run to determine the value of a feature, you want to track that event in your analytics system.

<Tabs>
  <Tab title="Async Client">
    For the async client, you can set up experiment tracking through the `Options`:

    ```python theme={null}
    import asyncio
    from growthbook import GrowthBookClient, Options, UserContext, Experiment, Result

    def on_experiment_viewed(experiment: Experiment, result: Result, user_context: UserContext):
        """Synchronous callback for experiment tracking (Fire-and-Forget)"""
        # Use whatever event tracking system you want
        user_id = result.hash_attribute or "anonymous"

        # For async analytics, you must schedule the task on the loop
        # without awaiting it (Fire-and-Forget)
        loop = asyncio.get_running_loop()
        loop.create_task(track_async(user_id, experiment, result))

    async def track_async(user_id, experiment, result):
        # This runs in the background
        await analytics.track_async(user_id, "Experiment Viewed", {
            'experimentId': experiment.key,
            'variationId': result.key,
            'variationValue': result.value,
            'inExperiment': result.in_experiment,
            'hashUsed': result.hash_used
        })
        print(f"Tracked experiment: {experiment.key} -> {result.value}")

    async def main():
        # Create client with experiment tracking
        client = GrowthBookClient(
            Options(
                api_host="https://cdn.growthbook.io",
                client_key="sdk-abc123",
                # Callback must be synchronous
                on_experiment_viewed=on_experiment_viewed
            )
        )

        try:
            await client.initialize()

            # Create user context
            user = UserContext(attributes={"id": "user_123", "premium": True})

            # Feature evaluations will automatically trigger tracking
            feature_value = await client.get_feature_value("button-color", "blue", user)

            # Run inline experiments (also triggers tracking)
            experiment = Experiment(
                key="pricing-test",
                variations=["$9.99", "$14.99", "$19.99"]
            )

            result = await client.run(experiment, user)
            print(f"Experiment result: {result.value}")

        finally:
            await client.close()

    asyncio.run(main())
    ```

    You can also use synchronous callbacks with the async client:

    ```python theme={null}
    def sync_experiment_tracker(experiment: Experiment, result: Result):
        """Synchronous callback that works with async client"""
        # Send to synchronous analytics service
        analytics.track("Experiment Viewed", {
            'experimentId': experiment.key,
            'variationId': result.key,
            'userId': result.hash_attribute
        })

    client = GrowthBookClient(
        Options(
            api_host="https://cdn.growthbook.io",
            client_key="sdk-abc123",
            on_experiment_viewed=sync_experiment_tracker  # Sync callback
        )
    )
    ```
  </Tab>

  <Tab title="Legacy Client">
    For the traditional client, pass the callback to the constructor:

    ```python theme={null}
    from growthbook import GrowthBook, Experiment, Result

    def on_experiment_viewed(experiment: Experiment, result: Result):
        """Callback for experiment tracking"""
      # Use whatever event tracking system you want
        user_id = result.hash_attribute or "anonymous"

        analytics.track(user_id, "Experiment Viewed", {
        'experimentId': experiment.key,
            'variationId': result.key,
            'variationValue': result.value,
            'inExperiment': result.in_experiment,
            'hashUsed': result.hash_used
      })

        print(f"Tracked experiment: {experiment.key} -> {result.value}")

    # Create GrowthBook instance with experiment tracking
    gb = GrowthBook(
        api_host="https://cdn.growthbook.io",
        client_key="sdk-abc123",
        attributes={"id": "user_123", "premium": True},
        on_experiment_viewed=on_experiment_viewed
    )

    gb.load_features()

    # Feature evaluations will automatically trigger tracking
    feature_value = gb.get_feature_value("button-color", "blue")

    # Run inline experiments (also triggers tracking)
    experiment = Experiment(
        key="pricing-test",
        variations=["$9.99", "$14.99", "$19.99"]
    )

    result = gb.run(experiment)
    print(f"Experiment result: {result.value}")

    gb.destroy()
    ```
  </Tab>
</Tabs>

### Tracking Plugins

**Available starting in version 1.3.0**

The Python SDK supports tracking plugins that provide automated event tracking with batching, error handling, and retry logic. This is the recommended approach for production applications as it handles edge cases and provides better reliability than custom tracking callbacks.

#### Built-in Tracking Plugin

The SDK includes a built-in tracking plugin that automatically batches and sends events:

<Tabs>
  <Tab title="Async Client">
    ```python theme={null}
    import asyncio
    from growthbook import GrowthBookClient, Options, UserContext, GrowthBookTrackingPlugin

    # Custom synchronous tracking callback
    def my_custom_tracker(experiment, result, user_context):
        """Process tracking event (Fire-and-Forget)"""
        loop = asyncio.get_running_loop()
        loop.create_task(process_async(experiment, result, user_context))

    async def process_async(experiment, result, user_context):
        # Send to your analytics system
        await analytics.track_async(
            user_id=user_context.attributes.get('id'),
            event_name="Experiment Viewed",
            properties={
                'experiment_id': experiment.key,
                'variation_id': result.key,
                'variation_value': result.value,
            }
        )

    async def main():
        # Create client with built-in tracking plugin
        client = GrowthBookClient(
            Options(
                api_host="https://cdn.growthbook.io",
                client_key="sdk-abc123",
                tracking_plugins=[
                    GrowthBookTrackingPlugin(
                        # Use the region you selected when setting up your Managed Warehouse
                        # (defaults to https://us-east-1.gb-ingest.com; https://eu-west-1.gb-ingest.com for EU)
                        ingestor_host="https://us-east-1.gb-ingest.com",
                        # Additional callback for custom analytics
                        additional_callback=my_custom_tracker
                    )
                ]
            )
        )

        try:
            await client.initialize()

            user = UserContext(attributes={"id": "user_123"})

            # Events are now automatically tracked and batched
            result1 = await client.get_feature_value("button-color", "blue", user)
            result2 = await client.is_on("premium-feature", user)

            # Plugin handles batching and sending automatically

        finally:
            await client.close()

    asyncio.run(main())
    ```
  </Tab>

  <Tab title="Legacy Client">
    ```python theme={null}
    from growthbook import GrowthBook, GrowthBookTrackingPlugin

    # Custom tracking callback for your analytics system
    def my_custom_tracker(experiment, result, user_context):
        """Process a tracking event"""
        analytics.track(
            user_id=user_context.attributes.get('id'),
            event_name="Experiment Viewed",
            properties={
                'experiment_id': experiment.key,
                'variation_id': result.key,
                'variation_value': result.value,
            }
        )

    # Create GrowthBook with tracking plugin
    gb = GrowthBook(
        api_host="https://cdn.growthbook.io",
        client_key="sdk-abc123",
        attributes={"id": "user_123"},
        plugins=[
            GrowthBookTrackingPlugin(
                # Use the region you selected when setting up your Managed Warehouse
                # (defaults to https://us-east-1.gb-ingest.com; https://eu-west-1.gb-ingest.com for EU)
                ingestor_host="https://us-east-1.gb-ingest.com",
                # Additional callback for custom analytics
                additional_callback=my_custom_tracker,
                # Number of events to accumulate before flushing (optional, default 10)
                batch_size=5,
                # Max seconds to wait before flushing a partial batch (optional, default 10.0)
                batch_timeout=10.0
            )
        ]
    )

    gb.load_features()

    # Events are now automatically tracked and batched
    result1 = gb.get_feature_value("button-color", "blue")
    result2 = gb.is_on("premium-feature")

    # Plugin handles batching and sending automatically

    gb.destroy()
    ```
  </Tab>
</Tabs>

#### Multiple Tracking Plugins

You can use multiple tracking plugins to send events to different analytics systems:

```python theme={null}
from growthbook import GrowthBookClient, Options, GrowthBookTrackingPlugin

# Different tracking callbacks
def segment_tracker(experiment, result, user_context):
    """Send events to Segment (Fire-and-Forget)"""
    loop = asyncio.get_running_loop()
    loop.create_task(segment_track_async(experiment, result))

async def segment_track_async(experiment, result):
     await segment.track_async(...)

def mixpanel_tracker(experiment, result, user_context):
    """Send events to Mixpanel (Fire-and-Forget)"""
    loop = asyncio.get_running_loop()
    loop.create_task(mixpanel.track_async(
        user_context.attributes.get('id'), "Experiment Viewed", {
            'experiment_id': experiment.key,
            'variation': result.value
        }
    ))

# Create client with multiple tracking plugins
client = GrowthBookClient(
    Options(
        api_host="https://cdn.growthbook.io",
        client_key="sdk-abc123",
        tracking_plugins=[
            GrowthBookTrackingPlugin(
                additional_callback=segment_tracker
            ),
            GrowthBookTrackingPlugin(
                additional_callback=mixpanel_tracker
            )
        ]
    )
)

# Events are now automatically sent to both Segment and Mixpanel
```

#### Tracking Plugin Benefits

The tracking plugin system provides several advantages over custom tracking callbacks:

* **Automatic Batching**: Events are batched together to reduce API calls
* **Error Handling**: Failed requests are automatically retried with exponential backoff
* **Non-blocking**: Tracking doesn't block feature evaluations
* **Configurable**: Batch sizes, intervals, and retry logic can be customized
* **Multiple Destinations**: Send events to multiple analytics systems simultaneously

#### Working with Traditional Callbacks

Tracking plugins work alongside your existing `on_experiment_viewed` callbacks:

```python theme={null}
def legacy_tracker(experiment, result):
    """Traditional tracking callback"""
    print(f"Legacy tracker: {experiment.key}")

client = GrowthBookClient(
    Options(
        api_host="https://cdn.growthbook.io",
        client_key="sdk-abc123",
        # Traditional callback still works
        on_experiment_viewed=legacy_tracker,
        # Plus new tracking plugins
        tracking_plugins=[
            GrowthBookTrackingPlugin(additional_callback=my_custom_tracker)
        ]
    )
)

# Both the legacy callback and plugin will be triggered
```

## Using Features

There are 3 main methods for interacting with features.

* `gb.is_on("feature-key")` returns true if the feature is on
* `gb.is_off("feature-key")` returns false if the feature is on
* `gb.get_feature_value("feature-key", "default")` returns the value of the feature with a fallback

In addition, you can use `gb.evalFeature("feature-key")` to get back a `FeatureResult` object with the following properties:

* **value** - The JSON-decoded value of the feature (or `None` if not defined)
* **on** and **off** - The JSON-decoded value cast to booleans
* **source** - Why the value was assigned to the user. One of `unknownFeature`, `defaultValue`, `force`, or `experiment`
* **experiment** - Information about the experiment (if any) which was used to assign the value to the user
* **experimentResult** - The result of the experiment (if any) which was used to assign the value to the user

## Sticky Bucketing

**Available starting in version 1.1.0**

By default GrowthBook does not persist assigned experiment variations for a user. We rely on deterministic hashing to ensure that the same user attributes always map to the same experiment variation. However, there are cases where this isn't good enough. For example, if you change targeting conditions in the middle of an experiment, users may stop being shown a variation even if they were previously bucketed into it.

Sticky Bucketing is a solution to these issues. You can provide a Sticky Bucket Service to the GrowthBook instance to persist previously seen variations and ensure that the user experience remains consistent for your users.

A sample `InMemoryStickyBucketService` implementation is provided for reference, but in production you will definitely want to implement your own version using a database, cookies, or similar for persistence.

Sticky Bucket documents contain three fields

* `attributeName` - The name of the attribute used to identify the user (e.g. `id`, `cookie_id`, etc.)
* `attributeValue` - The value of the attribute (e.g. `123`)
* `assignments` - A dictionary of persisted experiment assignments. For example: `{"exp1__0":"control"}`

The attributeName/attributeValue combo is the primary key.

<Tabs>
  <Tab title="Async Client">
    **Note**: The Async Client currently uses the synchronous sticky bucket interface. This means sticky bucket operations running in the main event loop may block. We recommend using a fast, local store (like the default in-memory one) or an optimized synchronous store.

    ```python theme={null}
    import asyncio
    from growthbook import GrowthBookClient, Options, UserContext
    # AbstractStickyBucketService is synchronous
    from growthbook import AbstractStickyBucketService

    class MyStickyBucketService(AbstractStickyBucketService):
        def get_assignments(self, attributeName, attributeValue):
            # Implementation must be synchronous
            return None

        def save_assignments(self, doc):
            # Implementation must be synchronous
            pass

    async def main():
        # Create sticky bucket service
        sticky_service = MyStickyBucketService()

        # Create client with sticky bucketing
        client = GrowthBookClient(
            Options(
                api_host="https://cdn.growthbook.io",
                client_key="sdk-abc123",
                sticky_bucket_service=sticky_service
            )
        )

        try:
            await client.initialize()

            # User will get consistent experiment assignments
            user = UserContext(attributes={"id": "user_123"})

            # ...
        finally:
            await client.close()
    ```
  </Tab>

  <Tab title="Legacy Client">
    For the traditional client, implement a synchronous sticky bucket service:

    ```python theme={null}
    from typing import Optional, Dict
    from growthbook import GrowthBook, AbstractStickyBucketService

    class MyStickyBucketService(AbstractStickyBucketService):
        """Synchronous sticky bucket service using database"""

        def __init__(self):
            # Initialize your database connection
            self.db = Database()  # Your DB client

        def get_assignments(self, attribute_name: str, attribute_value: str) -> Optional[Dict]:
            """Lookup a sticky bucket document"""
            try:
                return self.db.find({
                    "attributeName": attribute_name,
                    "attributeValue": attribute_value
                })
            except Exception as e:
                print(f"Error getting assignments: {e}")
                return None

        def save_assignments(self, doc: Dict) -> None:
            """Save sticky bucket assignments"""
            try:
                self.db.upsert({
                "attributeName": doc["attributeName"],
                "attributeValue": doc["attributeValue"]
            }, {
              "$set": {
                "assignments": doc["assignments"]
              }
            })
            except Exception as e:
                print(f"Error saving assignments: {e}")

    # Create GrowthBook with sticky bucketing
    gb = GrowthBook(
        api_host="https://cdn.growthbook.io",
        client_key="sdk-abc123",
        attributes={"id": "user_123"},
        sticky_bucket_service=MyStickyBucketService()
    )

    gb.load_features()

    # User will get consistent experiment assignments
    result1 = gb.get_feature_value("button-color", "blue")
    print(f"First assignment: {result1}")

    # Second time - retrieves saved assignment
    result2 = gb.get_feature_value("button-color", "blue")
    print(f"Consistent assignment: {result2}")

    # Run inline experiments with sticky bucketing
    from growthbook import Experiment

    experiment = Experiment(
        key="pricing-test",
        variations=["$9.99", "$14.99", "$19.99"]
    )

    exp_result = gb.run(experiment)
    print(f"Sticky experiment result: {exp_result.value}")

    gb.destroy()
    ```

    #### SQLite Implementation Example

    ```python theme={null}
    import sqlite3
    import json
    from growthbook import GrowthBook, AbstractStickyBucketService

    class SQLiteStickyBucketService(AbstractStickyBucketService):
        def __init__(self, db_path="sticky_buckets.db"):
            self.conn = sqlite3.connect(db_path)
            self.conn.execute('''
                CREATE TABLE IF NOT EXISTS sticky_buckets (
                    attribute_name TEXT,
                    attribute_value TEXT,
                    assignments TEXT,
                    PRIMARY KEY (attribute_name, attribute_value)
                )
            ''')
            self.conn.commit()

        def get_assignments(self, attribute_name: str, attribute_value: str) -> Optional[Dict]:
            cursor = self.conn.execute(
                "SELECT assignments FROM sticky_buckets WHERE attribute_name=? AND attribute_value=?",
                (attribute_name, attribute_value)
            )
            row = cursor.fetchone()
            if row:
                return {
                    "attributeName": attribute_name,
                    "attributeValue": attribute_value,
                    "assignments": json.loads(row[0])
                }
            return None

        def save_assignments(self, doc: Dict) -> None:
            self.conn.execute(
                "INSERT OR REPLACE INTO sticky_buckets (attribute_name, attribute_value, assignments) VALUES (?, ?, ?)",
                (doc["attributeName"], doc["attributeValue"], json.dumps(doc["assignments"]))
            )
            self.conn.commit()

    # Usage
    gb = GrowthBook(
        api_host="https://cdn.growthbook.io",
        client_key="sdk-abc123",
        attributes={"id": "user_123"},
        sticky_bucket_service=SQLiteStickyBucketService()
    )
    ```
  </Tab>
</Tabs>

## Inline Experiments

Instead of declaring all features up-front and referencing them by ids in your code, you can also just run an experiment directly. This is done with the `run` method:

<Tabs>
  <Tab title="Async Client">
    For the async client, use `await` with the `run` method:

    ```python theme={null}
    import asyncio
    from growthbook import GrowthBookClient, Options, UserContext, Experiment

    async def main():
        client = GrowthBookClient(
            Options(
                api_host="https://cdn.growthbook.io",
                client_key="sdk-abc123"
            )
        )

        try:
            await client.initialize()

            # Create user context
            user = UserContext(attributes={"id": "user_123", "country": "US"})

            # Simple experiment
    exp = Experiment(
                key="my-experiment",
                variations=["red", "blue", "green"]
            )

            # Run experiment (async)
            result = await client.run(exp, user)
            print(f"Variation: {result.value}")  # Either "red", "blue", or "green"

            # Complex experiment with all options
            complex_exp = Experiment(
                key="pricing-test",
                variations=[9.99, 14.99, 19.99],
                weights=[0.5, 0.3, 0.2],  # 50%, 30%, 20%
                coverage=0.8,  # Include 80% of users
                condition={"country": "US", "premium": True},
                hashAttribute="id",
                hashVersion=2,
                namespace=("pricing", 0, 0.5)
            )

            pricing_result = await client.run(complex_exp, user)

            if pricing_result.in_experiment:
                print(f"User is in pricing experiment: ${pricing_result.value}")
                print(f"Variation ID: {pricing_result.key}")
                print(f"Hash used: {pricing_result.hash_used}")
            else:
                print("User not in pricing experiment")

        finally:
            await client.close()

    asyncio.run(main())
    ```
  </Tab>

  <Tab title="Legacy Client">
    For the traditional client, call `run` directly:

    ```python theme={null}
    from growthbook import GrowthBook, Experiment

    # Create GrowthBook instance
    gb = GrowthBook(
        api_host="https://cdn.growthbook.io",
        client_key="sdk-abc123",
        attributes={"id": "user_123", "country": "US"}
    )

    gb.load_features()

    # Simple experiment
    exp = Experiment(
        key="my-experiment",
        variations=["red", "blue", "green"]
    )

    # Run experiment
    result = gb.run(exp)
    print(f"Variation: {result.value}")  # Either "red", "blue", or "green"

    # Complex experiment with all options
    complex_exp = Experiment(
        key="pricing-test",
        variations=[9.99, 14.99, 19.99],
        weights=[0.5, 0.3, 0.2],  # 50%, 30%, 20%
        coverage=0.8,  # Include 80% of users
        condition={"country": "US", "premium": True},
        hashAttribute="id",
        hashVersion=2,
        namespace=("pricing", 0, 0.5)
    )

    pricing_result = gb.run(complex_exp)

    if pricing_result.in_experiment:
        print(f"User is in pricing experiment: ${pricing_result.value}")
        print(f"Variation ID: {pricing_result.key}")
        print(f"Hash used: {pricing_result.hash_used}")
    else:
        print("User not in pricing experiment")

    gb.destroy()
    ```
  </Tab>
</Tabs>

As you can see, there are 2 required parameters for experiments, a string key, and an array of variations. Variations can be any data type, not just strings.

There are a number of additional settings to control the experiment behavior:

* **key** (`str`) - The globally unique tracking key for the experiment
* **variations** (`any[]`) - The different variations to choose between
* **seed** (`str`) - Added to the user id when hashing to determine a variation. Defaults to the experiment `key`
* **weights** (`float[]`) - How to weight traffic between variations. Must add to 1.
* **coverage** (`float`) - What percent of users should be included in the experiment (between 0 and 1, inclusive)
* **condition** (`dict`) - Targeting conditions
* **force** (`int`) - All users included in the experiment will be forced into the specified variation index
* **hashAttribute** (`string`) - What user attribute should be used to assign variations (defaults to "id")
* **hashVersion** (`int`) - What version of our hashing algorithm to use. We recommend using the latest version `2`.
* **namespace** (`tuple[str,float,float]`) - Used to run mutually exclusive experiments.

Here's an example that uses all of them:

```python theme={null}
exp = Experiment(
  key="my-test",
  # Variations can be a list of any data type
  variations=[0, 1],
  # If this changes, it will re-randomize all users in the experiment
  seed="abcdef123456",
  # Run a 40/60 experiment instead of the default even split (50/50)
  weights=[0.4, 0.6],
  # Only include 20% of users in the experiment
  coverage=0.2,
  # Targeting condition using a MongoDB-like syntax
  condition={
    'country': 'US',
    'browser': {
      '$in': ['chrome', 'firefox']
    }
  },
  # Use an alternate attribute for assigning variations (default is 'id')
  hashAttribute="sessionId",
  # Use the latest hashing algorithm
  hashVersion=2,
  # Includes the first 50% of users in the "pricing" namespace
  # Another experiment with a non-overlapping range will be mutually exclusive (e.g. [0.5, 1])
  namespace=("pricing", 0, 0.5),
)
```

### Inline Experiment Return Value

A call to `run` returns a `Result` object with a few useful properties:

```python theme={null}
result = gb.run(exp)

# If user is part of the experiment
print(result.inExperiment) # True or False

# The string key of the assigned variation
print(result.key) # e.g. "0" or "1"

# The value of the assigned variation
print(result.value) # e.g. "A" or "B"

# If the variation was randomly assigned by hashing user attributes
print(result.hashUsed) # True or False

# The user attribute used to assign a variation
print(result.hashAttribute) # "id"

# The value of that attribute
print(result.hashValue) # e.g. "123"
```

The `inExperiment` flag will be false if the user was excluded from being part of the experiment for any reason (e.g. failed targeting conditions).

The `hashUsed` flag will only be true if the user was randomly assigned a variation. If the user was forced into a specific variation instead, this flag will be false.

### Example Experiments

<Tabs>
  <Tab title="Async Client">
    3-way experiment with uneven variation weights:

    ```python theme={null}
    result = await client.run(
        Experiment(
            key="3-way-uneven",
            variations=["A", "B", "C"],
            weights=[0.5, 0.25, 0.25]
        ),
        user
    )
    ```
  </Tab>

  <Tab title="Legacy Client">
    3-way experiment with uneven variation weights:

    ```python theme={null}
    gb.run(Experiment(
        key="3-way-uneven",
        variations=["A", "B", "C"],
        weights=[0.5, 0.25, 0.25]
    ))
    ```
  </Tab>
</Tabs>

Slow rollout (10% of users who match the targeting condition):

<Tabs>
  <Tab title="Async Client">
    ```python theme={null}
    # Create user context with targeting attributes
    user = UserContext(attributes={
        "id": "123",
        "beta": True,
        "qa": True,
    })

    result = await client.run(
        Experiment(
            key="slow-rollout",
            variations=["A", "B"],
            coverage=0.1,
            condition={'beta': True}
        ),
        user
    )
    ```
  </Tab>

  <Tab title="Legacy Client">
    ```python theme={null}
    # User is marked as being in "qa" and "beta"
    gb = GrowthBook(
        attributes={
        "id": "123",
        "beta": True,
        "qa": True,
      },
    )

    gb.run(Experiment(
        key="slow-rollout",
        variations=["A", "B"],
        coverage=0.1,
        condition={'beta': True}
    ))
    ```
  </Tab>
</Tabs>

Complex variations:

<Tabs>
  <Tab title="Async Client">
    ```python theme={null}
    result = await client.run(
        Experiment(
            key="complex-variations",
            variations=[
                ("blue", "large"),
                ("green", "small")
            ],
        ),
        user
    )

    # Either "blue,large" OR "green,small"
    print(result.value[0] + "," + result.value[1])
    ```
  </Tab>

  <Tab title="Legacy Client">
    ```python theme={null}
    result = gb.run(Experiment(
        key="complex-variations",
        variations=[
        ("blue", "large"),
        ("green", "small")
      ],
    ))

    # Either "blue,large" OR "green,small"
    print(result.value[0] + "," + result.value[1])
    ```
  </Tab>
</Tabs>

Assign variations based on something other than user id:

<Tabs>
  <Tab title="Async Client">
    ```python theme={null}
    # Create user context with company attribute
    user = UserContext(attributes={
        "id": "123",
        "company": "growthbook"
    })

    # Users in the same company will always get the same variation
    result = await client.run(
        Experiment(
            key="by-company-id",
            variations=["A", "B"],
            hashAttribute="company"
        ),
        user
    )
    ```
  </Tab>

  <Tab title="Legacy Client">
    ```python theme={null}
    gb = GrowthBook(
        attributes={
        "id": "123",
        "company": "growthbook"
      }
    )

    # Users in the same company will always get the same variation
    gb.run(Experiment(
        key="by-company-id",
        variations=["A", "B"],
        hashAttribute="company"
    ))
    ```
  </Tab>
</Tabs>

## Working with Encrypted Features

The Python SDK supports encrypted feature flags for enhanced security. When encryption is enabled, the feature payload is encrypted before being sent from GrowthBook, and the SDK automatically decrypts it client-side.

<Tabs>
  <Tab title="Async Client">
    For the async client, provide the decryption key in the `Options`:

    ```python theme={null}
    import asyncio
    from growthbook import GrowthBookClient, Options, UserContext

    async def main():
        # Create client with decryption key
        client = GrowthBookClient(
            Options(
                api_host="https://cdn.growthbook.io",
                client_key="sdk-abc123",
                # Your decryption key from GrowthBook
                decryption_key="your-secret-key-here"
            )
        )

        try:
            await client.initialize()

            # Features are automatically decrypted
            user = UserContext(attributes={"id": "user_123"})
            feature_enabled = await client.is_on("encrypted-feature", user)

            print(f"Encrypted feature enabled: {feature_enabled}")

        finally:
            await client.close()

    asyncio.run(main())
    ```
  </Tab>

  <Tab title="Legacy Client">
    For the traditional client, pass the decryption key to the constructor:

    ```python theme={null}
    from growthbook import GrowthBook

    # Create GrowthBook with decryption key
    gb = GrowthBook(
        api_host="https://cdn.growthbook.io",
        client_key="sdk-abc123",
        # Your decryption key from GrowthBook
        decryption_key="your-secret-key-here",
        attributes={"id": "user_123"}
    )

    gb.load_features()

    # Features are automatically decrypted
    feature_enabled = gb.is_on("encrypted-feature")
    feature_value = gb.get_feature_value("encrypted-config", {"default": "value"})

    print(f"Encrypted feature enabled: {feature_enabled}")
    print(f"Encrypted config: {feature_value}")

    gb.destroy()
    ```
  </Tab>
</Tabs>

### Environment Variables

You can also set the decryption key via environment variable:

```bash theme={null}
export GROWTHBOOK_DECRYPTION_KEY="your-secret-key-here"
```

<Tabs>
  <Tab title="Async Client">
    ```python theme={null}
    import os
    from growthbook import GrowthBookClient, Options

    # Decryption key will be automatically picked up from environment
    client = GrowthBookClient(
        Options(
            api_host="https://cdn.growthbook.io",
            client_key="sdk-abc123",
            decryption_key=os.environ.get("GROWTHBOOK_DECRYPTION_KEY")
        )
    )
    ```
  </Tab>

  <Tab title="Legacy Client">
    ```python theme={null}
    import os
    from growthbook import GrowthBook

    # Decryption key will be automatically picked up from environment
    gb = GrowthBook(
        api_host="https://cdn.growthbook.io",
        client_key="sdk-abc123",
        # decryption_key will be read from GROWTHBOOK_DECRYPTION_KEY env var
        attributes={"id": "user_123"}
    )
    ```
  </Tab>
</Tabs>

### Error Handling

If decryption fails (wrong key, corrupted data, etc.), the SDK will log an error and treat all features as disabled/default values:

```python theme={null}
import logging

# Enable logging to see decryption errors
logging.basicConfig(level=logging.ERROR)
logger = logging.getLogger('growthbook')

# This will log errors if decryption fails
gb = GrowthBook(
    api_host="https://cdn.growthbook.io",
    client_key="sdk-abc123",
    decryption_key="wrong-key",  # This will cause decryption to fail
    attributes={"id": "user_123"}
)
```

## Logging

The GrowthBook SDK uses a Python logger with the name `growthbook` and includes helpful info for debugging as well as warnings/errors if something is misconfigured.

Here's an example of logging to the console

```python theme={null}
import logging

logger = logging.getLogger('growthbook')
logger.setLevel(logging.DEBUG)

handler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s %(name)s %(levelname)s %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
```

## Integration Examples

This section provides practical examples for integrating GrowthBook with popular web frameworks.

### Async Web Framework Integration (FastAPI)

The async client works great with modern async web frameworks like FastAPI:

```python theme={null}
from fastapi import FastAPI, Depends
from growthbook import GrowthBookClient, Options, UserContext

app = FastAPI()

# Create a single client instance (singleton)
gb_client = GrowthBookClient(
    Options(
        api_host="https://cdn.growthbook.io",
        client_key="sdk-abc123"
    )
)

@app.on_event("startup")
async def startup():
    # Initialize the client when the app starts
    await gb_client.initialize()

@app.on_event("shutdown")
async def shutdown():
    # Clean up when the app shuts down
    await gb_client.close()

@app.get("/")
async def root(user_id: str):
    # Create user context for the request
    user = UserContext(attributes={"id": user_id})

    # Use features - no need to pass client around
    show_new_ui = await gb_client.is_on("new-ui", user)
    discount_amount = await gb_client.get_feature_value("discount-percent", 0, user)

    return {
        "new_ui": show_new_ui,
        "discount": discount_amount
    }

@app.get("/experiment")
async def run_experiment(user_id: str):
    user = UserContext(attributes={"id": user_id})

    # Run inline experiments
    from growthbook import Experiment

    experiment = Experiment(
        key="button-color",
        variations=["red", "blue", "green"]
    )

    result = await gb_client.run(experiment, user)

    return {
        "variation": result.value,
        "in_experiment": result.in_experiment
    }
```

### Starlette Integration

```python theme={null}
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route
from growthbook import GrowthBookClient, Options, UserContext

# Create client instance
gb_client = GrowthBookClient(
    Options(
        api_host="https://cdn.growthbook.io",
        client_key="sdk-abc123"
    )
)

async def homepage(request):
    user_id = request.query_params.get('user_id', 'anonymous')
    user = UserContext(attributes={"id": user_id})

    feature_enabled = await gb_client.is_on("new-homepage", user)

    return JSONResponse({
        "new_homepage": feature_enabled,
        "user_id": user_id
    })

async def startup():
    await gb_client.initialize()

async def shutdown():
    await gb_client.close()

app = Starlette(
    routes=[
        Route('/', homepage),
    ],
    on_startup=[startup],
    on_shutdown=[shutdown]
)
```

### Traditional Web Frameworks (Django, Flask, etc.)

**For new projects, we recommend using the [Async Client](#async-client-recommended) instead for better performance.**

For traditional synchronous web frameworks, you should create a new `GrowthBook` instance for every incoming request and call `destroy()` at the end of the request to clean up resources.

#### Django Integration

In Django, this is best done with a simple middleware:

```python theme={null}
from growthbook import GrowthBook

def growthbook_middleware(get_response):
    def middleware(request):
        request.gb = GrowthBook(
            api_host="https://cdn.growthbook.io",
            client_key="sdk-abc123",
            attributes={
                "id": getattr(request.user, 'id', 'anonymous'),
                "loggedIn": request.user.is_authenticated,
                "country": request.META.get('HTTP_CF_IPCOUNTRY', 'US')
            }
        )
        request.gb.load_features()

        response = get_response(request)

        request.gb.destroy() # Cleanup

        return response
    return middleware
```

Then, you can easily use GrowthBook in any of your views:

```python theme={null}
def index(request):
    feature_enabled = request.gb.is_on("my-feature")
    button_color = request.gb.get_feature_value("button-color", "blue")

    return render(request, 'index.html', {
        'feature_enabled': feature_enabled,
        'button_color': button_color
    })
```

#### Flask Integration

```python theme={null}
from flask import Flask, g, request
from growthbook import GrowthBook

app = Flask(__name__)

@app.before_request
def before_request():
    g.gb = GrowthBook(
        api_host="https://cdn.growthbook.io",
        client_key="sdk-abc123",
        attributes={
            "id": request.headers.get('User-ID', 'anonymous'),
            "userAgent": request.user_agent.string,
            "url": request.url
        }
    )
    g.gb.load_features()

@app.teardown_request
def teardown_request(exception):
    gb = getattr(g, 'gb', None)
    if gb is not None:
        gb.destroy()

@app.route('/')
def index():
    feature_enabled = g.gb.is_on("new-layout")
    theme = g.gb.get_feature_value("theme", "light")

    return {
        "feature_enabled": feature_enabled,
        "theme": theme
    }
```

## Supported Features

<SdkSupportedFeatures sdk="python" />
